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