##// END OF EJS Templates
httppeer: always add x-hg* headers to Vary header...
Gregory Szorc -
r37573:930c433e default
parent child Browse files
Show More
@@ -1,658 +1,660
1 1 # httppeer.py - HTTP repository proxy classes for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from __future__ import absolute_import
10 10
11 11 import errno
12 12 import io
13 13 import os
14 14 import socket
15 15 import struct
16 16 import tempfile
17 17
18 18 from .i18n import _
19 19 from .thirdparty import (
20 20 cbor,
21 21 )
22 22 from . import (
23 23 bundle2,
24 24 error,
25 25 httpconnection,
26 26 pycompat,
27 27 statichttprepo,
28 28 url as urlmod,
29 29 util,
30 30 wireproto,
31 31 wireprotoframing,
32 32 wireprotov2server,
33 33 )
34 34
35 35 httplib = util.httplib
36 36 urlerr = util.urlerr
37 37 urlreq = util.urlreq
38 38
39 39 def encodevalueinheaders(value, header, limit):
40 40 """Encode a string value into multiple HTTP headers.
41 41
42 42 ``value`` will be encoded into 1 or more HTTP headers with the names
43 43 ``header-<N>`` where ``<N>`` is an integer starting at 1. Each header
44 44 name + value will be at most ``limit`` bytes long.
45 45
46 46 Returns an iterable of 2-tuples consisting of header names and
47 47 values as native strings.
48 48 """
49 49 # HTTP Headers are ASCII. Python 3 requires them to be unicodes,
50 50 # not bytes. This function always takes bytes in as arguments.
51 51 fmt = pycompat.strurl(header) + r'-%s'
52 52 # Note: it is *NOT* a bug that the last bit here is a bytestring
53 53 # and not a unicode: we're just getting the encoded length anyway,
54 54 # and using an r-string to make it portable between Python 2 and 3
55 55 # doesn't work because then the \r is a literal backslash-r
56 56 # instead of a carriage return.
57 57 valuelen = limit - len(fmt % r'000') - len(': \r\n')
58 58 result = []
59 59
60 60 n = 0
61 61 for i in xrange(0, len(value), valuelen):
62 62 n += 1
63 63 result.append((fmt % str(n), pycompat.strurl(value[i:i + valuelen])))
64 64
65 65 return result
66 66
67 67 def _wraphttpresponse(resp):
68 68 """Wrap an HTTPResponse with common error handlers.
69 69
70 70 This ensures that any I/O from any consumer raises the appropriate
71 71 error and messaging.
72 72 """
73 73 origread = resp.read
74 74
75 75 class readerproxy(resp.__class__):
76 76 def read(self, size=None):
77 77 try:
78 78 return origread(size)
79 79 except httplib.IncompleteRead as e:
80 80 # e.expected is an integer if length known or None otherwise.
81 81 if e.expected:
82 82 msg = _('HTTP request error (incomplete response; '
83 83 'expected %d bytes got %d)') % (e.expected,
84 84 len(e.partial))
85 85 else:
86 86 msg = _('HTTP request error (incomplete response)')
87 87
88 88 raise error.PeerTransportError(
89 89 msg,
90 90 hint=_('this may be an intermittent network failure; '
91 91 'if the error persists, consider contacting the '
92 92 'network or server operator'))
93 93 except httplib.HTTPException as e:
94 94 raise error.PeerTransportError(
95 95 _('HTTP request error (%s)') % e,
96 96 hint=_('this may be an intermittent network failure; '
97 97 'if the error persists, consider contacting the '
98 98 'network or server operator'))
99 99
100 100 resp.__class__ = readerproxy
101 101
102 102 class _multifile(object):
103 103 def __init__(self, *fileobjs):
104 104 for f in fileobjs:
105 105 if not util.safehasattr(f, 'length'):
106 106 raise ValueError(
107 107 '_multifile only supports file objects that '
108 108 'have a length but this one does not:', type(f), f)
109 109 self._fileobjs = fileobjs
110 110 self._index = 0
111 111
112 112 @property
113 113 def length(self):
114 114 return sum(f.length for f in self._fileobjs)
115 115
116 116 def read(self, amt=None):
117 117 if amt <= 0:
118 118 return ''.join(f.read() for f in self._fileobjs)
119 119 parts = []
120 120 while amt and self._index < len(self._fileobjs):
121 121 parts.append(self._fileobjs[self._index].read(amt))
122 122 got = len(parts[-1])
123 123 if got < amt:
124 124 self._index += 1
125 125 amt -= got
126 126 return ''.join(parts)
127 127
128 128 def seek(self, offset, whence=os.SEEK_SET):
129 129 if whence != os.SEEK_SET:
130 130 raise NotImplementedError(
131 131 '_multifile does not support anything other'
132 132 ' than os.SEEK_SET for whence on seek()')
133 133 if offset != 0:
134 134 raise NotImplementedError(
135 135 '_multifile only supports seeking to start, but that '
136 136 'could be fixed if you need it')
137 137 for f in self._fileobjs:
138 138 f.seek(0)
139 139 self._index = 0
140 140
141 141 def makev1commandrequest(ui, requestbuilder, caps, capablefn,
142 142 repobaseurl, cmd, args):
143 143 """Make an HTTP request to run a command for a version 1 client.
144 144
145 145 ``caps`` is a set of known server capabilities. The value may be
146 146 None if capabilities are not yet known.
147 147
148 148 ``capablefn`` is a function to evaluate a capability.
149 149
150 150 ``cmd``, ``args``, and ``data`` define the command, its arguments, and
151 151 raw data to pass to it.
152 152 """
153 153 if cmd == 'pushkey':
154 154 args['data'] = ''
155 155 data = args.pop('data', None)
156 156 headers = args.pop('headers', {})
157 157
158 158 ui.debug("sending %s command\n" % cmd)
159 159 q = [('cmd', cmd)]
160 160 headersize = 0
161 varyheaders = []
162 161 # Important: don't use self.capable() here or else you end up
163 162 # with infinite recursion when trying to look up capabilities
164 163 # for the first time.
165 164 postargsok = caps is not None and 'httppostargs' in caps
166 165
167 166 # Send arguments via POST.
168 167 if postargsok and args:
169 168 strargs = urlreq.urlencode(sorted(args.items()))
170 169 if not data:
171 170 data = strargs
172 171 else:
173 172 if isinstance(data, bytes):
174 173 i = io.BytesIO(data)
175 174 i.length = len(data)
176 175 data = i
177 176 argsio = io.BytesIO(strargs)
178 177 argsio.length = len(strargs)
179 178 data = _multifile(argsio, data)
180 179 headers[r'X-HgArgs-Post'] = len(strargs)
181 180 elif args:
182 181 # Calling self.capable() can infinite loop if we are calling
183 182 # "capabilities". But that command should never accept wire
184 183 # protocol arguments. So this should never happen.
185 184 assert cmd != 'capabilities'
186 185 httpheader = capablefn('httpheader')
187 186 if httpheader:
188 187 headersize = int(httpheader.split(',', 1)[0])
189 188
190 189 # Send arguments via HTTP headers.
191 190 if headersize > 0:
192 191 # The headers can typically carry more data than the URL.
193 192 encargs = urlreq.urlencode(sorted(args.items()))
194 193 for header, value in encodevalueinheaders(encargs, 'X-HgArg',
195 194 headersize):
196 195 headers[header] = value
197 varyheaders.append(header)
198 196 # Send arguments via query string (Mercurial <1.9).
199 197 else:
200 198 q += sorted(args.items())
201 199
202 200 qs = '?%s' % urlreq.urlencode(q)
203 201 cu = "%s%s" % (repobaseurl, qs)
204 202 size = 0
205 203 if util.safehasattr(data, 'length'):
206 204 size = data.length
207 205 elif data is not None:
208 206 size = len(data)
209 207 if data is not None and r'Content-Type' not in headers:
210 208 headers[r'Content-Type'] = r'application/mercurial-0.1'
211 209
212 210 # Tell the server we accept application/mercurial-0.2 and multiple
213 211 # compression formats if the server is capable of emitting those
214 212 # payloads.
215 213 protoparams = {'partial-pull'}
216 214
217 215 mediatypes = set()
218 216 if caps is not None:
219 217 mt = capablefn('httpmediatype')
220 218 if mt:
221 219 protoparams.add('0.1')
222 220 mediatypes = set(mt.split(','))
223 221
224 222 if '0.2tx' in mediatypes:
225 223 protoparams.add('0.2')
226 224
227 225 if '0.2tx' in mediatypes and capablefn('compression'):
228 226 # We /could/ compare supported compression formats and prune
229 227 # non-mutually supported or error if nothing is mutually supported.
230 228 # For now, send the full list to the server and have it error.
231 229 comps = [e.wireprotosupport().name for e in
232 230 util.compengines.supportedwireengines(util.CLIENTROLE)]
233 231 protoparams.add('comp=%s' % ','.join(comps))
234 232
235 233 if protoparams:
236 234 protoheaders = encodevalueinheaders(' '.join(sorted(protoparams)),
237 235 'X-HgProto',
238 236 headersize or 1024)
239 237 for header, value in protoheaders:
240 238 headers[header] = value
239
240 varyheaders = []
241 for header in headers:
242 if header.lower().startswith(r'x-hg'):
241 243 varyheaders.append(header)
242 244
243 245 if varyheaders:
244 headers[r'Vary'] = r','.join(varyheaders)
246 headers[r'Vary'] = r','.join(sorted(varyheaders))
245 247
246 248 req = requestbuilder(pycompat.strurl(cu), data, headers)
247 249
248 250 if data is not None:
249 251 ui.debug("sending %d bytes\n" % size)
250 252 req.add_unredirected_header(r'Content-Length', r'%d' % size)
251 253
252 254 return req, cu, qs
253 255
254 256 def sendrequest(ui, opener, req):
255 257 """Send a prepared HTTP request.
256 258
257 259 Returns the response object.
258 260 """
259 261 if (ui.debugflag
260 262 and ui.configbool('devel', 'debug.peer-request')):
261 263 dbg = ui.debug
262 264 line = 'devel-peer-request: %s\n'
263 265 dbg(line % '%s %s' % (req.get_method(), req.get_full_url()))
264 266 hgargssize = None
265 267
266 268 for header, value in sorted(req.header_items()):
267 269 if header.startswith('X-hgarg-'):
268 270 if hgargssize is None:
269 271 hgargssize = 0
270 272 hgargssize += len(value)
271 273 else:
272 274 dbg(line % ' %s %s' % (header, value))
273 275
274 276 if hgargssize is not None:
275 277 dbg(line % ' %d bytes of commands arguments in headers'
276 278 % hgargssize)
277 279
278 280 if req.has_data():
279 281 data = req.get_data()
280 282 length = getattr(data, 'length', None)
281 283 if length is None:
282 284 length = len(data)
283 285 dbg(line % ' %d bytes of data' % length)
284 286
285 287 start = util.timer()
286 288
287 289 try:
288 290 res = opener.open(req)
289 291 except urlerr.httperror as inst:
290 292 if inst.code == 401:
291 293 raise error.Abort(_('authorization failed'))
292 294 raise
293 295 except httplib.HTTPException as inst:
294 296 ui.debug('http error requesting %s\n' %
295 297 util.hidepassword(req.get_full_url()))
296 298 ui.traceback()
297 299 raise IOError(None, inst)
298 300 finally:
299 301 if ui.configbool('devel', 'debug.peer-request'):
300 302 dbg(line % ' finished in %.4f seconds (%s)'
301 303 % (util.timer() - start, res.code))
302 304
303 305 # Insert error handlers for common I/O failures.
304 306 _wraphttpresponse(res)
305 307
306 308 return res
307 309
308 310 def parsev1commandresponse(ui, baseurl, requrl, qs, resp, compressible):
309 311 # record the url we got redirected to
310 312 respurl = pycompat.bytesurl(resp.geturl())
311 313 if respurl.endswith(qs):
312 314 respurl = respurl[:-len(qs)]
313 315 if baseurl.rstrip('/') != respurl.rstrip('/'):
314 316 if not ui.quiet:
315 317 ui.warn(_('real URL is %s\n') % respurl)
316 318
317 319 try:
318 320 proto = pycompat.bytesurl(resp.getheader(r'content-type', r''))
319 321 except AttributeError:
320 322 proto = pycompat.bytesurl(resp.headers.get(r'content-type', r''))
321 323
322 324 safeurl = util.hidepassword(baseurl)
323 325 if proto.startswith('application/hg-error'):
324 326 raise error.OutOfBandError(resp.read())
325 327
326 328 # Pre 1.0 versions of Mercurial used text/plain and
327 329 # application/hg-changegroup. We don't support such old servers.
328 330 if not proto.startswith('application/mercurial-'):
329 331 ui.debug("requested URL: '%s'\n" % util.hidepassword(requrl))
330 332 raise error.RepoError(
331 333 _("'%s' does not appear to be an hg repository:\n"
332 334 "---%%<--- (%s)\n%s\n---%%<---\n")
333 335 % (safeurl, proto or 'no content-type', resp.read(1024)))
334 336
335 337 try:
336 338 version = proto.split('-', 1)[1]
337 339 version_info = tuple([int(n) for n in version.split('.')])
338 340 except ValueError:
339 341 raise error.RepoError(_("'%s' sent a broken Content-Type "
340 342 "header (%s)") % (safeurl, proto))
341 343
342 344 # TODO consider switching to a decompression reader that uses
343 345 # generators.
344 346 if version_info == (0, 1):
345 347 if compressible:
346 348 resp = util.compengines['zlib'].decompressorreader(resp)
347 349
348 350 elif version_info == (0, 2):
349 351 # application/mercurial-0.2 always identifies the compression
350 352 # engine in the payload header.
351 353 elen = struct.unpack('B', resp.read(1))[0]
352 354 ename = resp.read(elen)
353 355 engine = util.compengines.forwiretype(ename)
354 356
355 357 resp = engine.decompressorreader(resp)
356 358 else:
357 359 raise error.RepoError(_("'%s' uses newer protocol %s") %
358 360 (safeurl, version))
359 361
360 362 return respurl, resp
361 363
362 364 class httppeer(wireproto.wirepeer):
363 365 def __init__(self, ui, path, url, opener, requestbuilder, caps):
364 366 self.ui = ui
365 367 self._path = path
366 368 self._url = url
367 369 self._caps = caps
368 370 self._urlopener = opener
369 371 self._requestbuilder = requestbuilder
370 372
371 373 def __del__(self):
372 374 for h in self._urlopener.handlers:
373 375 h.close()
374 376 getattr(h, "close_all", lambda: None)()
375 377
376 378 # Begin of ipeerconnection interface.
377 379
378 380 def url(self):
379 381 return self._path
380 382
381 383 def local(self):
382 384 return None
383 385
384 386 def peer(self):
385 387 return self
386 388
387 389 def canpush(self):
388 390 return True
389 391
390 392 def close(self):
391 393 pass
392 394
393 395 # End of ipeerconnection interface.
394 396
395 397 # Begin of ipeercommands interface.
396 398
397 399 def capabilities(self):
398 400 return self._caps
399 401
400 402 # End of ipeercommands interface.
401 403
402 404 # look up capabilities only when needed
403 405
404 406 def _callstream(self, cmd, _compressible=False, **args):
405 407 args = pycompat.byteskwargs(args)
406 408
407 409 req, cu, qs = makev1commandrequest(self.ui, self._requestbuilder,
408 410 self._caps, self.capable,
409 411 self._url, cmd, args)
410 412
411 413 resp = sendrequest(self.ui, self._urlopener, req)
412 414
413 415 self._url, resp = parsev1commandresponse(self.ui, self._url, cu, qs,
414 416 resp, _compressible)
415 417
416 418 return resp
417 419
418 420 def _call(self, cmd, **args):
419 421 fp = self._callstream(cmd, **args)
420 422 try:
421 423 return fp.read()
422 424 finally:
423 425 # if using keepalive, allow connection to be reused
424 426 fp.close()
425 427
426 428 def _callpush(self, cmd, cg, **args):
427 429 # have to stream bundle to a temp file because we do not have
428 430 # http 1.1 chunked transfer.
429 431
430 432 types = self.capable('unbundle')
431 433 try:
432 434 types = types.split(',')
433 435 except AttributeError:
434 436 # servers older than d1b16a746db6 will send 'unbundle' as a
435 437 # boolean capability. They only support headerless/uncompressed
436 438 # bundles.
437 439 types = [""]
438 440 for x in types:
439 441 if x in bundle2.bundletypes:
440 442 type = x
441 443 break
442 444
443 445 tempname = bundle2.writebundle(self.ui, cg, None, type)
444 446 fp = httpconnection.httpsendfile(self.ui, tempname, "rb")
445 447 headers = {r'Content-Type': r'application/mercurial-0.1'}
446 448
447 449 try:
448 450 r = self._call(cmd, data=fp, headers=headers, **args)
449 451 vals = r.split('\n', 1)
450 452 if len(vals) < 2:
451 453 raise error.ResponseError(_("unexpected response:"), r)
452 454 return vals
453 455 except urlerr.httperror:
454 456 # Catch and re-raise these so we don't try and treat them
455 457 # like generic socket errors. They lack any values in
456 458 # .args on Python 3 which breaks our socket.error block.
457 459 raise
458 460 except socket.error as err:
459 461 if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
460 462 raise error.Abort(_('push failed: %s') % err.args[1])
461 463 raise error.Abort(err.args[1])
462 464 finally:
463 465 fp.close()
464 466 os.unlink(tempname)
465 467
466 468 def _calltwowaystream(self, cmd, fp, **args):
467 469 fh = None
468 470 fp_ = None
469 471 filename = None
470 472 try:
471 473 # dump bundle to disk
472 474 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
473 475 fh = os.fdopen(fd, r"wb")
474 476 d = fp.read(4096)
475 477 while d:
476 478 fh.write(d)
477 479 d = fp.read(4096)
478 480 fh.close()
479 481 # start http push
480 482 fp_ = httpconnection.httpsendfile(self.ui, filename, "rb")
481 483 headers = {r'Content-Type': r'application/mercurial-0.1'}
482 484 return self._callstream(cmd, data=fp_, headers=headers, **args)
483 485 finally:
484 486 if fp_ is not None:
485 487 fp_.close()
486 488 if fh is not None:
487 489 fh.close()
488 490 os.unlink(filename)
489 491
490 492 def _callcompressable(self, cmd, **args):
491 493 return self._callstream(cmd, _compressible=True, **args)
492 494
493 495 def _abort(self, exception):
494 496 raise exception
495 497
496 498 # TODO implement interface for version 2 peers
497 499 class httpv2peer(object):
498 500 def __init__(self, ui, repourl, opener):
499 501 self.ui = ui
500 502
501 503 if repourl.endswith('/'):
502 504 repourl = repourl[:-1]
503 505
504 506 self.url = repourl
505 507 self._opener = opener
506 508 # This is an its own attribute to facilitate extensions overriding
507 509 # the default type.
508 510 self._requestbuilder = urlreq.request
509 511
510 512 def close(self):
511 513 pass
512 514
513 515 # TODO require to be part of a batched primitive, use futures.
514 516 def _call(self, name, **args):
515 517 """Call a wire protocol command with arguments."""
516 518
517 519 # Having this early has a side-effect of importing wireprotov2server,
518 520 # which has the side-effect of ensuring commands are registered.
519 521
520 522 # TODO modify user-agent to reflect v2.
521 523 headers = {
522 524 r'Accept': wireprotov2server.FRAMINGTYPE,
523 525 r'Content-Type': wireprotov2server.FRAMINGTYPE,
524 526 }
525 527
526 528 # TODO permissions should come from capabilities results.
527 529 permission = wireproto.commandsv2[name].permission
528 530 if permission not in ('push', 'pull'):
529 531 raise error.ProgrammingError('unknown permission type: %s' %
530 532 permission)
531 533
532 534 permission = {
533 535 'push': 'rw',
534 536 'pull': 'ro',
535 537 }[permission]
536 538
537 539 url = '%s/api/%s/%s/%s' % (self.url, wireprotov2server.HTTPV2,
538 540 permission, name)
539 541
540 542 # TODO this should be part of a generic peer for the frame-based
541 543 # protocol.
542 544 reactor = wireprotoframing.clientreactor(hasmultiplesend=False,
543 545 buffersends=True)
544 546
545 547 request, action, meta = reactor.callcommand(name, args)
546 548 assert action == 'noop'
547 549
548 550 action, meta = reactor.flushcommands()
549 551 assert action == 'sendframes'
550 552
551 553 body = b''.join(map(bytes, meta['framegen']))
552 554 req = self._requestbuilder(pycompat.strurl(url), body, headers)
553 555 req.add_unredirected_header(r'Content-Length', r'%d' % len(body))
554 556
555 557 # TODO unify this code with httppeer.
556 558 try:
557 559 res = self._opener.open(req)
558 560 except urlerr.httperror as e:
559 561 if e.code == 401:
560 562 raise error.Abort(_('authorization failed'))
561 563
562 564 raise
563 565 except httplib.HTTPException as e:
564 566 self.ui.traceback()
565 567 raise IOError(None, e)
566 568
567 569 # TODO validate response type, wrap response to handle I/O errors.
568 570 # TODO more robust frame receiver.
569 571 results = []
570 572
571 573 while True:
572 574 frame = wireprotoframing.readframe(res)
573 575 if frame is None:
574 576 break
575 577
576 578 self.ui.note(_('received %r\n') % frame)
577 579
578 580 action, meta = reactor.onframerecv(frame)
579 581
580 582 if action == 'responsedata':
581 583 if meta['cbor']:
582 584 payload = util.bytesio(meta['data'])
583 585
584 586 decoder = cbor.CBORDecoder(payload)
585 587 while payload.tell() + 1 < len(meta['data']):
586 588 results.append(decoder.decode())
587 589 else:
588 590 results.append(meta['data'])
589 591 else:
590 592 error.ProgrammingError('unhandled action: %s' % action)
591 593
592 594 return results
593 595
594 596 def performhandshake(ui, url, opener, requestbuilder):
595 597 # The handshake is a request to the capabilities command.
596 598
597 599 caps = None
598 600 def capable(x):
599 601 raise error.ProgrammingError('should not be called')
600 602
601 603 req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps,
602 604 capable, url, 'capabilities',
603 605 {})
604 606
605 607 resp = sendrequest(ui, opener, req)
606 608
607 609 respurl, resp = parsev1commandresponse(ui, url, requrl, qs, resp,
608 610 compressible=False)
609 611
610 612 try:
611 613 rawcaps = resp.read()
612 614 finally:
613 615 resp.close()
614 616
615 617 return respurl, set(rawcaps.split())
616 618
617 619 def makepeer(ui, path, opener=None, requestbuilder=urlreq.request):
618 620 """Construct an appropriate HTTP peer instance.
619 621
620 622 ``opener`` is an ``url.opener`` that should be used to establish
621 623 connections, perform HTTP requests.
622 624
623 625 ``requestbuilder`` is the type used for constructing HTTP requests.
624 626 It exists as an argument so extensions can override the default.
625 627 """
626 628 u = util.url(path)
627 629 if u.query or u.fragment:
628 630 raise error.Abort(_('unsupported URL component: "%s"') %
629 631 (u.query or u.fragment))
630 632
631 633 # urllib cannot handle URLs with embedded user or passwd.
632 634 url, authinfo = u.authinfo()
633 635 ui.debug('using %s\n' % url)
634 636
635 637 opener = opener or urlmod.opener(ui, authinfo)
636 638
637 639 respurl, caps = performhandshake(ui, url, opener, requestbuilder)
638 640
639 641 return httppeer(ui, path, respurl, opener, requestbuilder, caps)
640 642
641 643 def instance(ui, path, create):
642 644 if create:
643 645 raise error.Abort(_('cannot create new http repository'))
644 646 try:
645 647 if path.startswith('https:') and not urlmod.has_https:
646 648 raise error.Abort(_('Python support for SSL and HTTPS '
647 649 'is not installed'))
648 650
649 651 inst = makepeer(ui, path)
650 652
651 653 return inst
652 654 except error.RepoError as httpexception:
653 655 try:
654 656 r = statichttprepo.instance(ui, "static-" + path, create)
655 657 ui.note(_('(falling back to static-http)\n'))
656 658 return r
657 659 except error.RepoError:
658 660 raise httpexception # use the original http RepoError instead
@@ -1,934 +1,934
1 1 #require killdaemons serve zstd
2 2
3 3 Client version is embedded in HTTP request and is effectively dynamic. Pin the
4 4 version so behavior is deterministic.
5 5
6 6 $ cat > fakeversion.py << EOF
7 7 > from mercurial import util
8 8 > util.version = lambda: '4.2'
9 9 > EOF
10 10
11 11 $ cat >> $HGRCPATH << EOF
12 12 > [extensions]
13 13 > fakeversion = `pwd`/fakeversion.py
14 14 > [devel]
15 15 > legacy.exchange = phases
16 16 > EOF
17 17
18 18 $ hg init server0
19 19 $ cd server0
20 20 $ touch foo
21 21 $ hg -q commit -A -m initial
22 22
23 23 Also disable compression because zstd is optional and causes output to vary
24 24 and because debugging partial responses is hard when compression is involved
25 25
26 26 $ cat > .hg/hgrc << EOF
27 27 > [extensions]
28 28 > badserver = $TESTDIR/badserverext.py
29 29 > [server]
30 30 > compressionengines = none
31 31 > EOF
32 32
33 33 Failure to accept() socket should result in connection related error message
34 34
35 35 $ hg serve --config badserver.closebeforeaccept=true -p $HGPORT -d --pid-file=hg.pid
36 36 $ cat hg.pid > $DAEMON_PIDS
37 37
38 38 $ hg clone http://localhost:$HGPORT/ clone
39 39 abort: error: $ECONNRESET$
40 40 [255]
41 41
42 42 (The server exits on its own, but there is a race between that and starting a new server.
43 43 So ensure the process is dead.)
44 44
45 45 $ killdaemons.py $DAEMON_PIDS
46 46
47 47 Failure immediately after accept() should yield connection related error message
48 48
49 49 $ hg serve --config badserver.closeafteraccept=true -p $HGPORT -d --pid-file=hg.pid
50 50 $ cat hg.pid > $DAEMON_PIDS
51 51
52 52 TODO: this usually outputs good results, but sometimes emits abort:
53 53 error: '' on FreeBSD and OS X.
54 54 What we ideally want are:
55 55
56 56 abort: error: $ECONNRESET$
57 57
58 58 The flakiness in this output was observable easily with
59 59 --runs-per-test=20 on macOS 10.12 during the freeze for 4.2.
60 60 $ hg clone http://localhost:$HGPORT/ clone
61 61 abort: error: * (glob)
62 62 [255]
63 63
64 64 $ killdaemons.py $DAEMON_PIDS
65 65
66 66 Failure to read all bytes in initial HTTP request should yield connection related error message
67 67
68 68 $ hg serve --config badserver.closeafterrecvbytes=1 -p $HGPORT -d --pid-file=hg.pid -E error.log
69 69 $ cat hg.pid > $DAEMON_PIDS
70 70
71 71 $ hg clone http://localhost:$HGPORT/ clone
72 72 abort: error: bad HTTP status line: ''
73 73 [255]
74 74
75 75 $ killdaemons.py $DAEMON_PIDS
76 76
77 77 $ cat error.log
78 78 readline(1 from 65537) -> (1) G
79 79 read limit reached; closing socket
80 80
81 81 $ rm -f error.log
82 82
83 83 Same failure, but server reads full HTTP request line
84 84
85 85 $ hg serve --config badserver.closeafterrecvbytes=40 -p $HGPORT -d --pid-file=hg.pid -E error.log
86 86 $ cat hg.pid > $DAEMON_PIDS
87 87 $ hg clone http://localhost:$HGPORT/ clone
88 88 abort: error: bad HTTP status line: ''
89 89 [255]
90 90
91 91 $ killdaemons.py $DAEMON_PIDS
92 92
93 93 $ cat error.log
94 94 readline(40 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
95 95 readline(7 from -1) -> (7) Accept-
96 96 read limit reached; closing socket
97 97
98 98 $ rm -f error.log
99 99
100 100 Failure on subsequent HTTP request on the same socket (cmd?batch)
101 101
102 102 $ hg serve --config badserver.closeafterrecvbytes=256,223 -p $HGPORT -d --pid-file=hg.pid -E error.log
103 103 $ cat hg.pid > $DAEMON_PIDS
104 104 $ hg clone http://localhost:$HGPORT/ clone
105 105 abort: error: bad HTTP status line: ''
106 106 [255]
107 107
108 108 $ killdaemons.py $DAEMON_PIDS
109 109
110 110 $ cat error.log
111 111 readline(256 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
112 112 readline(223 from -1) -> (27) Accept-Encoding: identity\r\n
113 113 readline(196 from -1) -> (19) vary: X-HgProto-1\r\n
114 114 readline(177 from -1) -> (27) x-hgproto-1: partial-pull\r\n
115 115 readline(150 from -1) -> (35) accept: application/mercurial-0.1\r\n
116 116 readline(115 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
117 117 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
118 118 readline(* from -1) -> (2) \r\n (glob)
119 119 write(36) -> HTTP/1.1 200 Script output follows\r\n
120 120 write(23) -> Server: badhttpserver\r\n
121 121 write(37) -> Date: $HTTP_DATE$\r\n
122 122 write(41) -> Content-Type: application/mercurial-0.1\r\n
123 123 write(21) -> Content-Length: 436\r\n
124 124 write(2) -> \r\n
125 125 write(436) -> batch branchmap bundle2=HG20%0Abookmarks%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps%0Arev-branch-cache changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
126 126 readline(4? from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n (glob)
127 127 readline(1? from -1) -> (1?) Accept-Encoding* (glob)
128 128 read limit reached; closing socket
129 129 readline(223 from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
130 130 readline(197 from -1) -> (27) Accept-Encoding: identity\r\n
131 131 readline(170 from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
132 132 readline(141 from -1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
133 133 readline(100 from -1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
134 134 readline(39 from -1) -> (35) accept: application/mercurial-0.1\r\n
135 135 readline(4 from -1) -> (4) host
136 136 read limit reached; closing socket
137 137
138 138 $ rm -f error.log
139 139
140 140 Failure to read getbundle HTTP request
141 141
142 142 $ hg serve --config badserver.closeafterrecvbytes=354,317,304 -p $HGPORT -d --pid-file=hg.pid -E error.log
143 143 $ cat hg.pid > $DAEMON_PIDS
144 144 $ hg clone http://localhost:$HGPORT/ clone
145 145 requesting all changes
146 146 abort: error: bad HTTP status line: ''
147 147 [255]
148 148
149 149 $ killdaemons.py $DAEMON_PIDS
150 150
151 151 $ cat error.log
152 152 readline(1 from -1) -> (1) x (?)
153 153 readline(1 from -1) -> (1) x (?)
154 154 readline(354 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
155 155 readline(321 from -1) -> (27) Accept-Encoding: identity\r\n
156 156 readline(294 from -1) -> (19) vary: X-HgProto-1\r\n
157 157 readline(275 from -1) -> (27) x-hgproto-1: partial-pull\r\n
158 158 readline(248 from -1) -> (35) accept: application/mercurial-0.1\r\n
159 159 readline(213 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
160 160 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
161 161 readline(* from -1) -> (2) \r\n (glob)
162 162 write(36) -> HTTP/1.1 200 Script output follows\r\n
163 163 write(23) -> Server: badhttpserver\r\n
164 164 write(37) -> Date: $HTTP_DATE$\r\n
165 165 write(41) -> Content-Type: application/mercurial-0.1\r\n
166 166 write(21) -> Content-Length: 436\r\n
167 167 write(2) -> \r\n
168 168 write(436) -> batch branchmap bundle2=HG20%0Abookmarks%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps%0Arev-branch-cache changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
169 169 readline(13? from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n (glob)
170 170 readline(1?? from -1) -> (27) Accept-Encoding: identity\r\n (glob)
171 171 readline(8? from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n (glob)
172 172 readline(5? from -1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n (glob)
173 173 readline(1? from -1) -> (1?) x-hgproto-1:* (glob)
174 174 read limit reached; closing socket
175 175 readline(317 from 65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
176 176 readline(291 from -1) -> (27) Accept-Encoding: identity\r\n
177 177 readline(264 from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
178 178 readline(235 from -1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
179 179 readline(194 from -1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
180 180 readline(133 from -1) -> (35) accept: application/mercurial-0.1\r\n
181 181 readline(98 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
182 182 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
183 183 readline(* from -1) -> (2) \r\n (glob)
184 184 write(36) -> HTTP/1.1 200 Script output follows\r\n
185 185 write(23) -> Server: badhttpserver\r\n
186 186 write(37) -> Date: $HTTP_DATE$\r\n
187 187 write(41) -> Content-Type: application/mercurial-0.1\r\n
188 188 write(20) -> Content-Length: 42\r\n
189 189 write(2) -> \r\n
190 190 write(42) -> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
191 191 readline(* from 65537) -> (*) GET /?cmd=getbundle HTTP* (glob)
192 192 read limit reached; closing socket
193 193 readline(304 from 65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
194 194 readline(274 from -1) -> (27) Accept-Encoding: identity\r\n
195 195 readline(247 from -1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
196 196 readline(218 from -1) -> (218) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtag
197 197 read limit reached; closing socket
198 198
199 199 $ rm -f error.log
200 200
201 201 Now do a variation using POST to send arguments
202 202
203 $ hg serve --config experimental.httppostargs=true --config badserver.closeafterrecvbytes=361,330 -p $HGPORT -d --pid-file=hg.pid -E error.log
203 $ hg serve --config experimental.httppostargs=true --config badserver.closeafterrecvbytes=375,344 -p $HGPORT -d --pid-file=hg.pid -E error.log
204 204 $ cat hg.pid > $DAEMON_PIDS
205 205
206 206 $ hg clone http://localhost:$HGPORT/ clone
207 207 abort: error: bad HTTP status line: ''
208 208 [255]
209 209
210 210 $ killdaemons.py $DAEMON_PIDS
211 211
212 212 $ cat error.log
213 readline(361 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
214 readline(328 from -1) -> (27) Accept-Encoding: identity\r\n
215 readline(301 from -1) -> (19) vary: X-HgProto-1\r\n
216 readline(282 from -1) -> (27) x-hgproto-1: partial-pull\r\n
217 readline(255 from -1) -> (35) accept: application/mercurial-0.1\r\n
218 readline(220 from -1) -> (2?) host: localhost:$HGPORT\r\n (glob)
213 readline(375 from 65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
214 readline(342 from -1) -> (27) Accept-Encoding: identity\r\n
215 readline(315 from -1) -> (19) vary: X-HgProto-1\r\n
216 readline(296 from -1) -> (27) x-hgproto-1: partial-pull\r\n
217 readline(269 from -1) -> (35) accept: application/mercurial-0.1\r\n
218 readline(234 from -1) -> (2?) host: localhost:$HGPORT\r\n (glob)
219 219 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
220 220 readline(* from -1) -> (2) \r\n (glob)
221 221 write(36) -> HTTP/1.1 200 Script output follows\r\n
222 222 write(23) -> Server: badhttpserver\r\n
223 223 write(37) -> Date: $HTTP_DATE$\r\n
224 224 write(41) -> Content-Type: application/mercurial-0.1\r\n
225 225 write(21) -> Content-Length: 449\r\n
226 226 write(2) -> \r\n
227 227 write(449) -> batch branchmap bundle2=HG20%0Abookmarks%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps%0Arev-branch-cache changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx httppostargs known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
228 readline\(14[67] from 65537\) -> \(2[67]\) POST /\?cmd=batch HTTP/1.1\\r\\n (re)
229 readline\(1(19|20) from -1\) -> \(27\) Accept-Encoding: identity\\r\\n (re)
230 readline(9? from -1) -> (41) content-type: application/mercurial-0.1\r\n (glob)
231 readline(5? from -1) -> (19) vary: X-HgProto-1\r\n (glob)
228 readline(1?? from 65537) -> (27) POST /?cmd=batch HTTP/1.1\r\n (glob)
229 readline(1?? from -1) -> (27) Accept-Encoding: identity\r\n (glob)
230 readline(1?? from -1) -> (41) content-type: application/mercurial-0.1\r\n (glob)
231 readline(6? from -1) -> (33) vary: X-HgArgs-Post,X-HgProto-1\r\n (glob)
232 232 readline(3? from -1) -> (19) x-hgargs-post: 28\r\n (glob)
233 233 readline(1? from -1) -> (1?) x-hgproto-1: * (glob)
234 234 read limit reached; closing socket
235 readline(330 from 65537) -> (27) POST /?cmd=batch HTTP/1.1\r\n
236 readline(303 from -1) -> (27) Accept-Encoding: identity\r\n
237 readline(276 from -1) -> (41) content-type: application/mercurial-0.1\r\n
238 readline(235 from -1) -> (19) vary: X-HgProto-1\r\n
235 readline(344 from 65537) -> (27) POST /?cmd=batch HTTP/1.1\r\n
236 readline(317 from -1) -> (27) Accept-Encoding: identity\r\n
237 readline(290 from -1) -> (41) content-type: application/mercurial-0.1\r\n
238 readline(249 from -1) -> (33) vary: X-HgArgs-Post,X-HgProto-1\r\n
239 239 readline(216 from -1) -> (19) x-hgargs-post: 28\r\n
240 240 readline(197 from -1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
241 241 readline(136 from -1) -> (35) accept: application/mercurial-0.1\r\n
242 242 readline(101 from -1) -> (20) content-length: 28\r\n
243 243 readline(81 from -1) -> (*) host: localhost:$HGPORT\r\n (glob)
244 244 readline(* from -1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n (glob)
245 245 readline(* from -1) -> (2) \r\n (glob)
246 246 read(* from 28) -> (*) cmds=* (glob)
247 247 read limit reached, closing socket
248 248 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
249 249
250 250 $ rm -f error.log
251 251
252 252 Now move on to partial server responses
253 253
254 254 Server sends a single character from the HTTP response line
255 255
256 256 $ hg serve --config badserver.closeaftersendbytes=1 -p $HGPORT -d --pid-file=hg.pid -E error.log
257 257 $ cat hg.pid > $DAEMON_PIDS
258 258
259 259 $ hg clone http://localhost:$HGPORT/ clone
260 260 abort: error: bad HTTP status line: H
261 261 [255]
262 262
263 263 $ killdaemons.py $DAEMON_PIDS
264 264
265 265 $ cat error.log
266 266 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
267 267 readline(-1) -> (27) Accept-Encoding: identity\r\n
268 268 readline(-1) -> (19) vary: X-HgProto-1\r\n
269 269 readline(-1) -> (27) x-hgproto-1: partial-pull\r\n
270 270 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
271 271 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
272 272 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
273 273 readline(-1) -> (2) \r\n
274 274 write(1 from 36) -> (0) H
275 275 write limit reached; closing socket
276 276 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
277 277
278 278 $ rm -f error.log
279 279
280 280 Server sends an incomplete capabilities response body
281 281
282 282 $ hg serve --config badserver.closeaftersendbytes=180 -p $HGPORT -d --pid-file=hg.pid -E error.log
283 283 $ cat hg.pid > $DAEMON_PIDS
284 284
285 285 $ hg clone http://localhost:$HGPORT/ clone
286 286 abort: HTTP request error (incomplete response; expected 416 bytes got 20)
287 287 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
288 288 [255]
289 289
290 290 $ killdaemons.py $DAEMON_PIDS
291 291
292 292 $ cat error.log
293 293 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
294 294 readline(-1) -> (27) Accept-Encoding: identity\r\n
295 295 readline(-1) -> (19) vary: X-HgProto-1\r\n
296 296 readline(-1) -> (27) x-hgproto-1: partial-pull\r\n
297 297 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
298 298 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
299 299 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
300 300 readline(-1) -> (2) \r\n
301 301 write(36 from 36) -> (144) HTTP/1.1 200 Script output follows\r\n
302 302 write(23 from 23) -> (121) Server: badhttpserver\r\n
303 303 write(37 from 37) -> (84) Date: $HTTP_DATE$\r\n
304 304 write(41 from 41) -> (43) Content-Type: application/mercurial-0.1\r\n
305 305 write(21 from 21) -> (22) Content-Length: 436\r\n
306 306 write(2 from 2) -> (20) \r\n
307 307 write(20 from 436) -> (0) batch branchmap bund
308 308 write limit reached; closing socket
309 309
310 310 $ rm -f error.log
311 311
312 312 Server sends incomplete headers for batch request
313 313
314 314 $ hg serve --config badserver.closeaftersendbytes=714 -p $HGPORT -d --pid-file=hg.pid -E error.log
315 315 $ cat hg.pid > $DAEMON_PIDS
316 316
317 317 TODO this output is horrible
318 318
319 319 $ hg clone http://localhost:$HGPORT/ clone
320 320 abort: 'http://localhost:$HGPORT/' does not appear to be an hg repository:
321 321 ---%<--- (applicat)
322 322
323 323 ---%<---
324 324 !
325 325 [255]
326 326
327 327 $ killdaemons.py $DAEMON_PIDS
328 328
329 329 $ cat error.log
330 330 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
331 331 readline(-1) -> (27) Accept-Encoding: identity\r\n
332 332 readline(-1) -> (19) vary: X-HgProto-1\r\n
333 333 readline(-1) -> (27) x-hgproto-1: partial-pull\r\n
334 334 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
335 335 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
336 336 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
337 337 readline(-1) -> (2) \r\n
338 338 write(36 from 36) -> (678) HTTP/1.1 200 Script output follows\r\n
339 339 write(23 from 23) -> (655) Server: badhttpserver\r\n
340 340 write(37 from 37) -> (618) Date: $HTTP_DATE$\r\n
341 341 write(41 from 41) -> (577) Content-Type: application/mercurial-0.1\r\n
342 342 write(21 from 21) -> (556) Content-Length: 436\r\n
343 343 write(2 from 2) -> (554) \r\n
344 344 write(436 from 436) -> (118) batch branchmap bundle2=HG20%0Abookmarks%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps%0Arev-branch-cache changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
345 345 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
346 346 readline(-1) -> (27) Accept-Encoding: identity\r\n
347 347 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
348 348 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
349 349 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
350 350 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
351 351 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
352 352 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
353 353 readline(-1) -> (2) \r\n
354 354 write(36 from 36) -> (82) HTTP/1.1 200 Script output follows\r\n
355 355 write(23 from 23) -> (59) Server: badhttpserver\r\n
356 356 write(37 from 37) -> (22) Date: $HTTP_DATE$\r\n
357 357 write(22 from 41) -> (0) Content-Type: applicat
358 358 write limit reached; closing socket
359 359 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
360 360
361 361 $ rm -f error.log
362 362
363 363 Server sends an incomplete HTTP response body to batch request
364 364
365 365 $ hg serve --config badserver.closeaftersendbytes=779 -p $HGPORT -d --pid-file=hg.pid -E error.log
366 366 $ cat hg.pid > $DAEMON_PIDS
367 367
368 368 TODO client spews a stack due to uncaught ValueError in batch.results()
369 369 #if no-chg
370 370 $ hg clone http://localhost:$HGPORT/ clone 2> /dev/null
371 371 [1]
372 372 #else
373 373 $ hg clone http://localhost:$HGPORT/ clone 2> /dev/null
374 374 [255]
375 375 #endif
376 376
377 377 $ killdaemons.py $DAEMON_PIDS
378 378
379 379 $ cat error.log
380 380 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
381 381 readline(-1) -> (27) Accept-Encoding: identity\r\n
382 382 readline(-1) -> (19) vary: X-HgProto-1\r\n
383 383 readline(-1) -> (27) x-hgproto-1: partial-pull\r\n
384 384 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
385 385 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
386 386 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
387 387 readline(-1) -> (2) \r\n
388 388 write(36 from 36) -> (743) HTTP/1.1 200 Script output follows\r\n
389 389 write(23 from 23) -> (720) Server: badhttpserver\r\n
390 390 write(37 from 37) -> (683) Date: $HTTP_DATE$\r\n
391 391 write(41 from 41) -> (642) Content-Type: application/mercurial-0.1\r\n
392 392 write(21 from 21) -> (621) Content-Length: 436\r\n
393 393 write(2 from 2) -> (619) \r\n
394 394 write(436 from 436) -> (183) batch branchmap bundle2=HG20%0Abookmarks%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps%0Arev-branch-cache changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
395 395 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
396 396 readline(-1) -> (27) Accept-Encoding: identity\r\n
397 397 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
398 398 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
399 399 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
400 400 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
401 401 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
402 402 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
403 403 readline(-1) -> (2) \r\n
404 404 write(36 from 36) -> (147) HTTP/1.1 200 Script output follows\r\n
405 405 write(23 from 23) -> (124) Server: badhttpserver\r\n
406 406 write(37 from 37) -> (87) Date: $HTTP_DATE$\r\n
407 407 write(41 from 41) -> (46) Content-Type: application/mercurial-0.1\r\n
408 408 write(20 from 20) -> (26) Content-Length: 42\r\n
409 409 write(2 from 2) -> (24) \r\n
410 410 write(24 from 42) -> (0) 96ee1d7354c4ad7372047672
411 411 write limit reached; closing socket
412 412
413 413 $ rm -f error.log
414 414
415 415 Server sends incomplete headers for getbundle response
416 416
417 417 $ hg serve --config badserver.closeaftersendbytes=926 -p $HGPORT -d --pid-file=hg.pid -E error.log
418 418 $ cat hg.pid > $DAEMON_PIDS
419 419
420 420 TODO this output is terrible
421 421
422 422 $ hg clone http://localhost:$HGPORT/ clone
423 423 requesting all changes
424 424 abort: 'http://localhost:$HGPORT/' does not appear to be an hg repository:
425 425 ---%<--- (application/mercuri)
426 426
427 427 ---%<---
428 428 !
429 429 [255]
430 430
431 431 $ killdaemons.py $DAEMON_PIDS
432 432
433 433 $ cat error.log
434 434 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
435 435 readline(-1) -> (27) Accept-Encoding: identity\r\n
436 436 readline(-1) -> (19) vary: X-HgProto-1\r\n
437 437 readline(-1) -> (27) x-hgproto-1: partial-pull\r\n
438 438 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
439 439 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
440 440 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
441 441 readline(-1) -> (2) \r\n
442 442 write(36 from 36) -> (890) HTTP/1.1 200 Script output follows\r\n
443 443 write(23 from 23) -> (867) Server: badhttpserver\r\n
444 444 write(37 from 37) -> (830) Date: $HTTP_DATE$\r\n
445 445 write(41 from 41) -> (789) Content-Type: application/mercurial-0.1\r\n
446 446 write(21 from 21) -> (768) Content-Length: 436\r\n
447 447 write(2 from 2) -> (766) \r\n
448 448 write(436 from 436) -> (330) batch branchmap bundle2=HG20%0Abookmarks%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps%0Arev-branch-cache changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
449 449 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
450 450 readline(-1) -> (27) Accept-Encoding: identity\r\n
451 451 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
452 452 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
453 453 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
454 454 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
455 455 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
456 456 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
457 457 readline(-1) -> (2) \r\n
458 458 write(36 from 36) -> (294) HTTP/1.1 200 Script output follows\r\n
459 459 write(23 from 23) -> (271) Server: badhttpserver\r\n
460 460 write(37 from 37) -> (234) Date: $HTTP_DATE$\r\n
461 461 write(41 from 41) -> (193) Content-Type: application/mercurial-0.1\r\n
462 462 write(20 from 20) -> (173) Content-Length: 42\r\n
463 463 write(2 from 2) -> (171) \r\n
464 464 write(42 from 42) -> (129) 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
465 465 readline(65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
466 466 readline(-1) -> (27) Accept-Encoding: identity\r\n
467 467 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
468 468 readline(-1) -> (461) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=96ee1d7354c4ad7372047672c36a1f561e3a6a4c&listkeys=phases%2Cbookmarks\r\n
469 469 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
470 470 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
471 471 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
472 472 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
473 473 readline(-1) -> (2) \r\n
474 474 write(36 from 36) -> (93) HTTP/1.1 200 Script output follows\r\n
475 475 write(23 from 23) -> (70) Server: badhttpserver\r\n
476 476 write(37 from 37) -> (33) Date: $HTTP_DATE$\r\n
477 477 write(33 from 41) -> (0) Content-Type: application/mercuri
478 478 write limit reached; closing socket
479 479 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
480 480
481 481 $ rm -f error.log
482 482
483 483 Server sends empty HTTP body for getbundle
484 484
485 485 $ hg serve --config badserver.closeaftersendbytes=964 -p $HGPORT -d --pid-file=hg.pid -E error.log
486 486 $ cat hg.pid > $DAEMON_PIDS
487 487
488 488 $ hg clone http://localhost:$HGPORT/ clone
489 489 requesting all changes
490 490 abort: HTTP request error (incomplete response)
491 491 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
492 492 [255]
493 493
494 494 $ killdaemons.py $DAEMON_PIDS
495 495
496 496 $ cat error.log
497 497 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
498 498 readline(-1) -> (27) Accept-Encoding: identity\r\n
499 499 readline(-1) -> (19) vary: X-HgProto-1\r\n
500 500 readline(-1) -> (27) x-hgproto-1: partial-pull\r\n
501 501 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
502 502 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
503 503 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
504 504 readline(-1) -> (2) \r\n
505 505 write(36 from 36) -> (928) HTTP/1.1 200 Script output follows\r\n
506 506 write(23 from 23) -> (905) Server: badhttpserver\r\n
507 507 write(37 from 37) -> (868) Date: $HTTP_DATE$\r\n
508 508 write(41 from 41) -> (827) Content-Type: application/mercurial-0.1\r\n
509 509 write(21 from 21) -> (806) Content-Length: 436\r\n
510 510 write(2 from 2) -> (804) \r\n
511 511 write(436 from 436) -> (368) batch branchmap bundle2=HG20%0Abookmarks%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps%0Arev-branch-cache changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
512 512 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
513 513 readline(-1) -> (27) Accept-Encoding: identity\r\n
514 514 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
515 515 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
516 516 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
517 517 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
518 518 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
519 519 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
520 520 readline(-1) -> (2) \r\n
521 521 write(36 from 36) -> (332) HTTP/1.1 200 Script output follows\r\n
522 522 write(23 from 23) -> (309) Server: badhttpserver\r\n
523 523 write(37 from 37) -> (272) Date: $HTTP_DATE$\r\n
524 524 write(41 from 41) -> (231) Content-Type: application/mercurial-0.1\r\n
525 525 write(20 from 20) -> (211) Content-Length: 42\r\n
526 526 write(2 from 2) -> (209) \r\n
527 527 write(42 from 42) -> (167) 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
528 528 readline(65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
529 529 readline(-1) -> (27) Accept-Encoding: identity\r\n
530 530 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
531 531 readline(-1) -> (461) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=96ee1d7354c4ad7372047672c36a1f561e3a6a4c&listkeys=phases%2Cbookmarks\r\n
532 532 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
533 533 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
534 534 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
535 535 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
536 536 readline(-1) -> (2) \r\n
537 537 write(36 from 36) -> (131) HTTP/1.1 200 Script output follows\r\n
538 538 write(23 from 23) -> (108) Server: badhttpserver\r\n
539 539 write(37 from 37) -> (71) Date: $HTTP_DATE$\r\n
540 540 write(41 from 41) -> (30) Content-Type: application/mercurial-0.2\r\n
541 541 write(28 from 28) -> (2) Transfer-Encoding: chunked\r\n
542 542 write(2 from 2) -> (0) \r\n
543 543 write limit reached; closing socket
544 544 write(36) -> HTTP/1.1 500 Internal Server Error\r\n
545 545
546 546 $ rm -f error.log
547 547
548 548 Server sends partial compression string
549 549
550 550 $ hg serve --config badserver.closeaftersendbytes=988 -p $HGPORT -d --pid-file=hg.pid -E error.log
551 551 $ cat hg.pid > $DAEMON_PIDS
552 552
553 553 $ hg clone http://localhost:$HGPORT/ clone
554 554 requesting all changes
555 555 abort: HTTP request error (incomplete response)
556 556 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
557 557 [255]
558 558
559 559 $ killdaemons.py $DAEMON_PIDS
560 560
561 561 $ cat error.log
562 562 readline(65537) -> (33) GET /?cmd=capabilities HTTP/1.1\r\n
563 563 readline(-1) -> (27) Accept-Encoding: identity\r\n
564 564 readline(-1) -> (19) vary: X-HgProto-1\r\n
565 565 readline(-1) -> (27) x-hgproto-1: partial-pull\r\n
566 566 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
567 567 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
568 568 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
569 569 readline(-1) -> (2) \r\n
570 570 write(36 from 36) -> (952) HTTP/1.1 200 Script output follows\r\n
571 571 write(23 from 23) -> (929) Server: badhttpserver\r\n
572 572 write(37 from 37) -> (892) Date: $HTTP_DATE$\r\n
573 573 write(41 from 41) -> (851) Content-Type: application/mercurial-0.1\r\n
574 574 write(21 from 21) -> (830) Content-Length: 436\r\n
575 575 write(2 from 2) -> (828) \r\n
576 576 write(436 from 436) -> (392) batch branchmap bundle2=HG20%0Abookmarks%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps%0Arev-branch-cache changegroupsubset compression=none getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
577 577 readline(65537) -> (26) GET /?cmd=batch HTTP/1.1\r\n
578 578 readline(-1) -> (27) Accept-Encoding: identity\r\n
579 579 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
580 580 readline(-1) -> (41) x-hgarg-1: cmds=heads+%3Bknown+nodes%3D\r\n
581 581 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
582 582 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
583 583 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
584 584 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
585 585 readline(-1) -> (2) \r\n
586 586 write(36 from 36) -> (356) HTTP/1.1 200 Script output follows\r\n
587 587 write(23 from 23) -> (333) Server: badhttpserver\r\n
588 588 write(37 from 37) -> (296) Date: $HTTP_DATE$\r\n
589 589 write(41 from 41) -> (255) Content-Type: application/mercurial-0.1\r\n
590 590 write(20 from 20) -> (235) Content-Length: 42\r\n
591 591 write(2 from 2) -> (233) \r\n
592 592 write(42 from 42) -> (191) 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n;
593 593 readline(65537) -> (30) GET /?cmd=getbundle HTTP/1.1\r\n
594 594 readline(-1) -> (27) Accept-Encoding: identity\r\n
595 595 readline(-1) -> (29) vary: X-HgArg-1,X-HgProto-1\r\n
596 596 readline(-1) -> (461) x-hgarg-1: bookmarks=1&bundlecaps=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2&cg=1&common=0000000000000000000000000000000000000000&heads=96ee1d7354c4ad7372047672c36a1f561e3a6a4c&listkeys=phases%2Cbookmarks\r\n
597 597 readline(-1) -> (61) x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
598 598 readline(-1) -> (35) accept: application/mercurial-0.1\r\n
599 599 readline(-1) -> (2?) host: localhost:$HGPORT\r\n (glob)
600 600 readline(-1) -> (49) user-agent: mercurial/proto-1.0 (Mercurial 4.2)\r\n
601 601 readline(-1) -> (2) \r\n
602 602 write(36 from 36) -> (155) HTTP/1.1 200 Script output follows\r\n
603 603 write(23 from 23) -> (132) Server: badhttpserver\r\n
604 604 write(37 from 37) -> (95) Date: $HTTP_DATE$\r\n
605 605 write(41 from 41) -> (54) Content-Type: application/mercurial-0.2\r\n
606 606 write(28 from 28) -> (26) Transfer-Encoding: chunked\r\n
607 607 write(2 from 2) -> (24) \r\n
608 608 write(6 from 6) -> (18) 1\\r\\n\x04\\r\\n (esc)
609 609 write(9 from 9) -> (9) 4\r\nnone\r\n
610 610 write(9 from 9) -> (0) 4\r\nHG20\r\n
611 611 write limit reached; closing socket
612 612 write(27) -> 15\r\nInternal Server Error\r\n
613 613
614 614 $ rm -f error.log
615 615
616 616 Server sends partial bundle2 header magic
617 617
618 618 $ hg serve --config badserver.closeaftersendbytes=985 -p $HGPORT -d --pid-file=hg.pid -E error.log
619 619 $ cat hg.pid > $DAEMON_PIDS
620 620
621 621 $ hg clone http://localhost:$HGPORT/ clone
622 622 requesting all changes
623 623 abort: HTTP request error (incomplete response; expected 1 bytes got 3)
624 624 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
625 625 [255]
626 626
627 627 $ killdaemons.py $DAEMON_PIDS
628 628
629 629 $ tail -7 error.log
630 630 write(28 from 28) -> (23) Transfer-Encoding: chunked\r\n
631 631 write(2 from 2) -> (21) \r\n
632 632 write(6 from 6) -> (15) 1\\r\\n\x04\\r\\n (esc)
633 633 write(9 from 9) -> (6) 4\r\nnone\r\n
634 634 write(6 from 9) -> (0) 4\r\nHG2
635 635 write limit reached; closing socket
636 636 write(27) -> 15\r\nInternal Server Error\r\n
637 637
638 638 $ rm -f error.log
639 639
640 640 Server sends incomplete bundle2 stream params length
641 641
642 642 $ hg serve --config badserver.closeaftersendbytes=994 -p $HGPORT -d --pid-file=hg.pid -E error.log
643 643 $ cat hg.pid > $DAEMON_PIDS
644 644
645 645 $ hg clone http://localhost:$HGPORT/ clone
646 646 requesting all changes
647 647 abort: HTTP request error (incomplete response; expected 1 bytes got 3)
648 648 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
649 649 [255]
650 650
651 651 $ killdaemons.py $DAEMON_PIDS
652 652
653 653 $ tail -8 error.log
654 654 write(28 from 28) -> (32) Transfer-Encoding: chunked\r\n
655 655 write(2 from 2) -> (30) \r\n
656 656 write(6 from 6) -> (24) 1\\r\\n\x04\\r\\n (esc)
657 657 write(9 from 9) -> (15) 4\r\nnone\r\n
658 658 write(9 from 9) -> (6) 4\r\nHG20\r\n
659 659 write(6 from 9) -> (0) 4\\r\\n\x00\x00\x00 (esc)
660 660 write limit reached; closing socket
661 661 write(27) -> 15\r\nInternal Server Error\r\n
662 662
663 663 $ rm -f error.log
664 664
665 665 Servers stops after bundle2 stream params header
666 666
667 667 $ hg serve --config badserver.closeaftersendbytes=997 -p $HGPORT -d --pid-file=hg.pid -E error.log
668 668 $ cat hg.pid > $DAEMON_PIDS
669 669
670 670 $ hg clone http://localhost:$HGPORT/ clone
671 671 requesting all changes
672 672 abort: HTTP request error (incomplete response)
673 673 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
674 674 [255]
675 675
676 676 $ killdaemons.py $DAEMON_PIDS
677 677
678 678 $ tail -8 error.log
679 679 write(28 from 28) -> (35) Transfer-Encoding: chunked\r\n
680 680 write(2 from 2) -> (33) \r\n
681 681 write(6 from 6) -> (27) 1\\r\\n\x04\\r\\n (esc)
682 682 write(9 from 9) -> (18) 4\r\nnone\r\n
683 683 write(9 from 9) -> (9) 4\r\nHG20\r\n
684 684 write(9 from 9) -> (0) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
685 685 write limit reached; closing socket
686 686 write(27) -> 15\r\nInternal Server Error\r\n
687 687
688 688 $ rm -f error.log
689 689
690 690 Server stops sending after bundle2 part header length
691 691
692 692 $ hg serve --config badserver.closeaftersendbytes=1006 -p $HGPORT -d --pid-file=hg.pid -E error.log
693 693 $ cat hg.pid > $DAEMON_PIDS
694 694
695 695 $ hg clone http://localhost:$HGPORT/ clone
696 696 requesting all changes
697 697 abort: HTTP request error (incomplete response)
698 698 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
699 699 [255]
700 700
701 701 $ killdaemons.py $DAEMON_PIDS
702 702
703 703 $ tail -9 error.log
704 704 write(28 from 28) -> (44) Transfer-Encoding: chunked\r\n
705 705 write(2 from 2) -> (42) \r\n
706 706 write(6 from 6) -> (36) 1\\r\\n\x04\\r\\n (esc)
707 707 write(9 from 9) -> (27) 4\r\nnone\r\n
708 708 write(9 from 9) -> (18) 4\r\nHG20\r\n
709 709 write(9 from 9) -> (9) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
710 710 write(9 from 9) -> (0) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
711 711 write limit reached; closing socket
712 712 write(27) -> 15\r\nInternal Server Error\r\n
713 713
714 714 $ rm -f error.log
715 715
716 716 Server stops sending after bundle2 part header
717 717
718 718 $ hg serve --config badserver.closeaftersendbytes=1053 -p $HGPORT -d --pid-file=hg.pid -E error.log
719 719 $ cat hg.pid > $DAEMON_PIDS
720 720
721 721 $ hg clone http://localhost:$HGPORT/ clone
722 722 requesting all changes
723 723 adding changesets
724 724 transaction abort!
725 725 rollback completed
726 726 abort: HTTP request error (incomplete response)
727 727 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
728 728 [255]
729 729
730 730 $ killdaemons.py $DAEMON_PIDS
731 731
732 732 $ tail -10 error.log
733 733 write(28 from 28) -> (91) Transfer-Encoding: chunked\r\n
734 734 write(2 from 2) -> (89) \r\n
735 735 write(6 from 6) -> (83) 1\\r\\n\x04\\r\\n (esc)
736 736 write(9 from 9) -> (74) 4\r\nnone\r\n
737 737 write(9 from 9) -> (65) 4\r\nHG20\r\n
738 738 write(9 from 9) -> (56) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
739 739 write(9 from 9) -> (47) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
740 740 write(47 from 47) -> (0) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
741 741 write limit reached; closing socket
742 742 write(27) -> 15\r\nInternal Server Error\r\n
743 743
744 744 $ rm -f error.log
745 745
746 746 Server stops after bundle2 part payload chunk size
747 747
748 748 $ hg serve --config badserver.closeaftersendbytes=1074 -p $HGPORT -d --pid-file=hg.pid -E error.log
749 749 $ cat hg.pid > $DAEMON_PIDS
750 750
751 751 $ hg clone http://localhost:$HGPORT/ clone
752 752 requesting all changes
753 753 adding changesets
754 754 transaction abort!
755 755 rollback completed
756 756 abort: HTTP request error (incomplete response; expected 459 bytes got 7)
757 757 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
758 758 [255]
759 759
760 760 $ killdaemons.py $DAEMON_PIDS
761 761
762 762 $ tail -11 error.log
763 763 write(2 from 2) -> (110) \r\n
764 764 write(6 from 6) -> (104) 1\\r\\n\x04\\r\\n (esc)
765 765 write(9 from 9) -> (95) 4\r\nnone\r\n
766 766 write(9 from 9) -> (86) 4\r\nHG20\r\n
767 767 write(9 from 9) -> (77) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
768 768 write(9 from 9) -> (68) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
769 769 write(47 from 47) -> (21) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
770 770 write(9 from 9) -> (12) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
771 771 write(12 from 473) -> (0) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1d (esc)
772 772 write limit reached; closing socket
773 773 write(27) -> 15\r\nInternal Server Error\r\n
774 774
775 775 $ rm -f error.log
776 776
777 777 Server stops sending in middle of bundle2 payload chunk
778 778
779 779 $ hg serve --config badserver.closeaftersendbytes=1535 -p $HGPORT -d --pid-file=hg.pid -E error.log
780 780 $ cat hg.pid > $DAEMON_PIDS
781 781
782 782 $ hg clone http://localhost:$HGPORT/ clone
783 783 requesting all changes
784 784 adding changesets
785 785 transaction abort!
786 786 rollback completed
787 787 abort: HTTP request error (incomplete response)
788 788 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
789 789 [255]
790 790
791 791 $ killdaemons.py $DAEMON_PIDS
792 792
793 793 $ tail -12 error.log
794 794 write(28 from 28) -> (573) Transfer-Encoding: chunked\r\n
795 795 write(2 from 2) -> (571) \r\n
796 796 write(6 from 6) -> (565) 1\\r\\n\x04\\r\\n (esc)
797 797 write(9 from 9) -> (556) 4\r\nnone\r\n
798 798 write(9 from 9) -> (547) 4\r\nHG20\r\n
799 799 write(9 from 9) -> (538) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
800 800 write(9 from 9) -> (529) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
801 801 write(47 from 47) -> (482) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
802 802 write(9 from 9) -> (473) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
803 803 write(473 from 473) -> (0) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
804 804 write limit reached; closing socket
805 805 write(27) -> 15\r\nInternal Server Error\r\n
806 806
807 807 $ rm -f error.log
808 808
809 809 Server stops sending after 0 length payload chunk size
810 810
811 811 $ hg serve --config badserver.closeaftersendbytes=1566 -p $HGPORT -d --pid-file=hg.pid -E error.log
812 812 $ cat hg.pid > $DAEMON_PIDS
813 813
814 814 $ hg clone http://localhost:$HGPORT/ clone
815 815 requesting all changes
816 816 adding changesets
817 817 adding manifests
818 818 adding file changes
819 819 added 1 changesets with 1 changes to 1 files
820 820 transaction abort!
821 821 rollback completed
822 822 abort: HTTP request error (incomplete response; expected 23 bytes got 9)
823 823 (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator)
824 824 [255]
825 825
826 826 $ killdaemons.py $DAEMON_PIDS
827 827
828 828 $ tail -13 error.log
829 829 write(6 from 6) -> (596) 1\\r\\n\x04\\r\\n (esc)
830 830 write(9 from 9) -> (587) 4\r\nnone\r\n
831 831 write(9 from 9) -> (578) 4\r\nHG20\r\n
832 832 write(9 from 9) -> (569) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
833 833 write(9 from 9) -> (560) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
834 834 write(47 from 47) -> (513) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
835 835 write(9 from 9) -> (504) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
836 836 write(473 from 473) -> (31) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
837 837 write(9 from 9) -> (22) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
838 838 write(9 from 9) -> (13) 4\\r\\n\x00\x00\x00 \\r\\n (esc)
839 839 write(13 from 38) -> (0) 20\\r\\n\x08LISTKEYS (esc)
840 840 write limit reached; closing socket
841 841 write(27) -> 15\r\nInternal Server Error\r\n
842 842
843 843 $ rm -f error.log
844 844
845 845 Server stops sending after 0 part bundle part header (indicating end of bundle2 payload)
846 846 This is before the 0 size chunked transfer part that signals end of HTTP response.
847 847
848 848 # $ hg serve --config badserver.closeaftersendbytes=1741 -p $HGPORT -d --pid-file=hg.pid -E error.log
849 849 $ hg serve --config badserver.closeaftersendbytes=1848 -p $HGPORT -d --pid-file=hg.pid -E error.log
850 850 $ cat hg.pid > $DAEMON_PIDS
851 851
852 852 $ hg clone http://localhost:$HGPORT/ clone
853 853 requesting all changes
854 854 adding changesets
855 855 adding manifests
856 856 adding file changes
857 857 added 1 changesets with 1 changes to 1 files
858 858 new changesets 96ee1d7354c4
859 859 updating to branch default
860 860 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
861 861
862 862 $ killdaemons.py $DAEMON_PIDS
863 863
864 864 $ tail -22 error.log
865 865 write(9 from 9) -> (851) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
866 866 write(9 from 9) -> (842) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
867 867 write(47 from 47) -> (795) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
868 868 write(9 from 9) -> (786) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
869 869 write(473 from 473) -> (313) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
870 870 write(9 from 9) -> (304) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
871 871 write(9 from 9) -> (295) 4\\r\\n\x00\x00\x00 \\r\\n (esc)
872 872 write(38 from 38) -> (257) 20\\r\\n\x08LISTKEYS\x00\x00\x00\x01\x01\x00 \x06namespacephases\\r\\n (esc)
873 873 write(9 from 9) -> (248) 4\\r\\n\x00\x00\x00:\\r\\n (esc)
874 874 write(64 from 64) -> (184) 3a\r\n96ee1d7354c4ad7372047672c36a1f561e3a6a4c 1\npublishing True\r\n
875 875 write(9 from 9) -> (175) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
876 876 write(9 from 9) -> (166) 4\\r\\n\x00\x00\x00#\\r\\n (esc)
877 877 write(41 from 41) -> (125) 23\\r\\n\x08LISTKEYS\x00\x00\x00\x02\x01\x00 namespacebookmarks\\r\\n (esc)
878 878 write(9 from 9) -> (116) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
879 879 write(9 from 9) -> (107) 4\\r\\n\x00\x00\x00\x1d\\r\\n (esc)
880 880 write(35 from 35) -> (72) 1d\\r\\n\x16CACHE:REV-BRANCH-CACHE\x00\x00\x00\x03\x00\x00\\r\\n (esc)
881 881 write(9 from 9) -> (63) 4\\r\\n\x00\x00\x00'\\r\\n (esc)
882 882 write(45 from 45) -> (18) 27\\r\\n\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00default\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\\r\\n (esc)
883 883 write(9 from 9) -> (9) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
884 884 write(9 from 9) -> (0) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
885 885 write limit reached; closing socket
886 886 write(27) -> 15\r\nInternal Server Error\r\n
887 887
888 888 $ rm -f error.log
889 889 $ rm -rf clone
890 890
891 891 Server sends a size 0 chunked-transfer size without terminating \r\n
892 892
893 893 $ hg serve --config badserver.closeaftersendbytes=1851 -p $HGPORT -d --pid-file=hg.pid -E error.log
894 894 $ cat hg.pid > $DAEMON_PIDS
895 895
896 896 $ hg clone http://localhost:$HGPORT/ clone
897 897 requesting all changes
898 898 adding changesets
899 899 adding manifests
900 900 adding file changes
901 901 added 1 changesets with 1 changes to 1 files
902 902 new changesets 96ee1d7354c4
903 903 updating to branch default
904 904 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
905 905
906 906 $ killdaemons.py $DAEMON_PIDS
907 907
908 908 $ tail -23 error.log
909 909 write(9 from 9) -> (854) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
910 910 write(9 from 9) -> (845) 4\\r\\n\x00\x00\x00)\\r\\n (esc)
911 911 write(47 from 47) -> (798) 29\\r\\n\x0bCHANGEGROUP\x00\x00\x00\x00\x01\x01\x07\x02 \x01version02nbchanges1\\r\\n (esc)
912 912 write(9 from 9) -> (789) 4\\r\\n\x00\x00\x01\xd2\\r\\n (esc)
913 913 write(473 from 473) -> (316) 1d2\\r\\n\x00\x00\x00\xb2\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>6a3df4de388f3c4f8e28f4f9a814299a3cbb5f50\\ntest\\n0 0\\nfoo\\n\\ninitial\x00\x00\x00\x00\x00\x00\x00\xa1j=\xf4\xde8\x8f<O\x8e(\xf4\xf9\xa8\x14)\x9a<\xbb_P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00b80de5d138758541c5f05265ad144ab9fa86d1db\\n\x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00h\xb8\\r\xe5\xd18u\x85A\xc5\xf0Re\xad\x14J\xb9\xfa\x86\xd1\xdb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\x00\x00\x00\x00\x00\x00\x00\x00\\r\\n (esc)
914 914 write(9 from 9) -> (307) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
915 915 write(9 from 9) -> (298) 4\\r\\n\x00\x00\x00 \\r\\n (esc)
916 916 write(38 from 38) -> (260) 20\\r\\n\x08LISTKEYS\x00\x00\x00\x01\x01\x00 \x06namespacephases\\r\\n (esc)
917 917 write(9 from 9) -> (251) 4\\r\\n\x00\x00\x00:\\r\\n (esc)
918 918 write(64 from 64) -> (187) 3a\r\n96ee1d7354c4ad7372047672c36a1f561e3a6a4c 1\npublishing True\r\n
919 919 write(9 from 9) -> (178) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
920 920 write(9 from 9) -> (169) 4\\r\\n\x00\x00\x00#\\r\\n (esc)
921 921 write(41 from 41) -> (128) 23\\r\\n\x08LISTKEYS\x00\x00\x00\x02\x01\x00 namespacebookmarks\\r\\n (esc)
922 922 write(9 from 9) -> (119) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
923 923 write(9 from 9) -> (110) 4\\r\\n\x00\x00\x00\x1d\\r\\n (esc)
924 924 write(35 from 35) -> (75) 1d\\r\\n\x16CACHE:REV-BRANCH-CACHE\x00\x00\x00\x03\x00\x00\\r\\n (esc)
925 925 write(9 from 9) -> (66) 4\\r\\n\x00\x00\x00'\\r\\n (esc)
926 926 write(45 from 45) -> (21) 27\\r\\n\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00default\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL\\r\\n (esc)
927 927 write(9 from 9) -> (12) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
928 928 write(9 from 9) -> (3) 4\\r\\n\x00\x00\x00\x00\\r\\n (esc)
929 929 write(3 from 5) -> (0) 0\r\n
930 930 write limit reached; closing socket
931 931 write(27) -> 15\r\nInternal Server Error\r\n
932 932
933 933 $ rm -f error.log
934 934 $ rm -rf clone
General Comments 0
You need to be logged in to leave comments. Login now