Show More
@@ -252,3 +252,6 class UnsupportedBundleSpecification(Exc | |||||
252 |
|
252 | |||
253 | class CorruptedState(Exception): |
|
253 | class CorruptedState(Exception): | |
254 | """error raised when a command is not able to read its state from file""" |
|
254 | """error raised when a command is not able to read its state from file""" | |
|
255 | ||||
|
256 | class RichIOError(Abort): | |||
|
257 | """An IOError that can also have a hint attached.""" |
@@ -75,6 +75,41 def encodevalueinheaders(value, header, | |||||
75 |
|
75 | |||
76 | return result |
|
76 | return result | |
77 |
|
77 | |||
|
78 | def _wraphttpresponse(resp): | |||
|
79 | """Wrap an HTTPResponse with common error handlers. | |||
|
80 | ||||
|
81 | This ensures that any I/O from any consumer raises the appropriate | |||
|
82 | error and messaging. | |||
|
83 | """ | |||
|
84 | origread = resp.read | |||
|
85 | ||||
|
86 | class readerproxy(resp.__class__): | |||
|
87 | def read(self, size=None): | |||
|
88 | try: | |||
|
89 | return origread(size) | |||
|
90 | except httplib.IncompleteRead as e: | |||
|
91 | # e.expected is an integer if length known or None otherwise. | |||
|
92 | if e.expected: | |||
|
93 | msg = _('HTTP request error (incomplete response; ' | |||
|
94 | 'expected %d bytes got %d)') % (e.expected, | |||
|
95 | len(e.partial)) | |||
|
96 | else: | |||
|
97 | msg = _('HTTP request error (incomplete response)') | |||
|
98 | ||||
|
99 | raise error.RichIOError( | |||
|
100 | msg, | |||
|
101 | hint=_('this may be an intermittent network failure; ' | |||
|
102 | 'if the error persists, consider contacting the ' | |||
|
103 | 'network or server operator')) | |||
|
104 | except httplib.HTTPException as e: | |||
|
105 | raise error.RichIOError( | |||
|
106 | _('HTTP request error (%s)') % e, | |||
|
107 | hint=_('this may be an intermittent failure; ' | |||
|
108 | 'if the error persists, consider contacting the ' | |||
|
109 | 'network or server operator')) | |||
|
110 | ||||
|
111 | resp.__class__ = readerproxy | |||
|
112 | ||||
78 | class httppeer(wireproto.wirepeer): |
|
113 | class httppeer(wireproto.wirepeer): | |
79 | def __init__(self, ui, path): |
|
114 | def __init__(self, ui, path): | |
80 | self.path = path |
|
115 | self.path = path | |
@@ -223,6 +258,10 class httppeer(wireproto.wirepeer): | |||||
223 | self.ui.debug('http error while sending %s command\n' % cmd) |
|
258 | self.ui.debug('http error while sending %s command\n' % cmd) | |
224 | self.ui.traceback() |
|
259 | self.ui.traceback() | |
225 | raise IOError(None, inst) |
|
260 | raise IOError(None, inst) | |
|
261 | ||||
|
262 | # Insert error handlers for common I/O failures. | |||
|
263 | _wraphttpresponse(resp) | |||
|
264 | ||||
226 | # record the url we got redirected to |
|
265 | # record the url we got redirected to | |
227 | resp_url = resp.geturl() |
|
266 | resp_url = resp.geturl() | |
228 | if resp_url.endswith(qs): |
|
267 | if resp_url.endswith(qs): |
@@ -267,10 +267,10 Server sends an incomplete capabilities | |||||
267 | $ hg --config badserver.closeaftersendbytes=180 serve -p $HGPORT -d --pid-file=hg.pid -E error.log |
|
267 | $ hg --config badserver.closeaftersendbytes=180 serve -p $HGPORT -d --pid-file=hg.pid -E error.log | |
268 | $ cat hg.pid > $DAEMON_PIDS |
|
268 | $ cat hg.pid > $DAEMON_PIDS | |
269 |
|
269 | |||
270 | TODO client spews a stack due to uncaught httplib.IncompleteRead |
|
270 | $ hg clone http://localhost:$HGPORT/ clone | |
271 |
|
271 | abort: HTTP request error (incomplete response; expected 385 bytes got 20) | ||
272 | $ hg clone http://localhost:$HGPORT/ clone 2> /dev/null |
|
272 | (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator) | |
273 |
[ |
|
273 | [255] | |
274 |
|
274 | |||
275 | $ killdaemons.py $DAEMON_PIDS |
|
275 | $ killdaemons.py $DAEMON_PIDS | |
276 |
|
276 | |||
@@ -461,11 +461,11 Server sends empty HTTP body for getbund | |||||
461 | $ hg --config badserver.closeaftersendbytes=933 serve -p $HGPORT -d --pid-file=hg.pid -E error.log |
|
461 | $ hg --config badserver.closeaftersendbytes=933 serve -p $HGPORT -d --pid-file=hg.pid -E error.log | |
462 | $ cat hg.pid > $DAEMON_PIDS |
|
462 | $ cat hg.pid > $DAEMON_PIDS | |
463 |
|
463 | |||
464 | TODO client spews a stack due to uncaught httplib.IncompleteRead |
|
464 | $ hg clone http://localhost:$HGPORT/ clone | |
465 |
|
||||
466 | $ hg clone http://localhost:$HGPORT/ clone 2> /dev/null |
|
|||
467 | requesting all changes |
|
465 | requesting all changes | |
468 | [1] |
|
466 | abort: HTTP request error (incomplete response) | |
|
467 | (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator) | |||
|
468 | [255] | |||
469 |
|
469 | |||
470 | $ killdaemons.py $DAEMON_PIDS |
|
470 | $ killdaemons.py $DAEMON_PIDS | |
471 |
|
471 | |||
@@ -525,11 +525,11 Server sends partial compression string | |||||
525 | $ hg --config badserver.closeaftersendbytes=945 serve -p $HGPORT -d --pid-file=hg.pid -E error.log |
|
525 | $ hg --config badserver.closeaftersendbytes=945 serve -p $HGPORT -d --pid-file=hg.pid -E error.log | |
526 | $ cat hg.pid > $DAEMON_PIDS |
|
526 | $ cat hg.pid > $DAEMON_PIDS | |
527 |
|
527 | |||
528 | TODO client spews a stack due to uncaught httplib.IncompleteRead |
|
528 | $ hg clone http://localhost:$HGPORT/ clone | |
529 |
|
||||
530 | $ hg clone http://localhost:$HGPORT/ clone 2> /dev/null |
|
|||
531 | requesting all changes |
|
529 | requesting all changes | |
532 | [1] |
|
530 | abort: HTTP request error (incomplete response; expected 1 bytes got 3) | |
|
531 | (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator) | |||
|
532 | [255] | |||
533 |
|
533 | |||
534 | $ killdaemons.py $DAEMON_PIDS |
|
534 | $ killdaemons.py $DAEMON_PIDS | |
535 |
|
535 | |||
@@ -593,7 +593,8 Server sends partial bundle2 header magi | |||||
593 |
|
593 | |||
594 | $ hg clone http://localhost:$HGPORT/ clone |
|
594 | $ hg clone http://localhost:$HGPORT/ clone | |
595 | requesting all changes |
|
595 | requesting all changes | |
596 | abort: connection ended unexpectedly |
|
596 | abort: HTTP request error (incomplete response; expected 1 bytes got 3) | |
|
597 | (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator) | |||
597 | [255] |
|
598 | [255] | |
598 |
|
599 | |||
599 | $ killdaemons.py $DAEMON_PIDS |
|
600 | $ killdaemons.py $DAEMON_PIDS | |
@@ -616,7 +617,8 Server sends incomplete bundle2 stream p | |||||
616 |
|
617 | |||
617 | $ hg clone http://localhost:$HGPORT/ clone |
|
618 | $ hg clone http://localhost:$HGPORT/ clone | |
618 | requesting all changes |
|
619 | requesting all changes | |
619 | abort: connection ended unexpectedly |
|
620 | abort: HTTP request error (incomplete response; expected 1 bytes got 3) | |
|
621 | (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator) | |||
620 | [255] |
|
622 | [255] | |
621 |
|
623 | |||
622 | $ killdaemons.py $DAEMON_PIDS |
|
624 | $ killdaemons.py $DAEMON_PIDS | |
@@ -640,7 +642,8 Servers stops after bundle2 stream param | |||||
640 |
|
642 | |||
641 | $ hg clone http://localhost:$HGPORT/ clone |
|
643 | $ hg clone http://localhost:$HGPORT/ clone | |
642 | requesting all changes |
|
644 | requesting all changes | |
643 | abort: connection ended unexpectedly |
|
645 | abort: HTTP request error (incomplete response) | |
|
646 | (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator) | |||
644 | [255] |
|
647 | [255] | |
645 |
|
648 | |||
646 | $ killdaemons.py $DAEMON_PIDS |
|
649 | $ killdaemons.py $DAEMON_PIDS | |
@@ -664,7 +667,8 Server stops sending after bundle2 part | |||||
664 |
|
667 | |||
665 | $ hg clone http://localhost:$HGPORT/ clone |
|
668 | $ hg clone http://localhost:$HGPORT/ clone | |
666 | requesting all changes |
|
669 | requesting all changes | |
667 | abort: connection ended unexpectedly |
|
670 | abort: HTTP request error (incomplete response) | |
|
671 | (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator) | |||
668 | [255] |
|
672 | [255] | |
669 |
|
673 | |||
670 | $ killdaemons.py $DAEMON_PIDS |
|
674 | $ killdaemons.py $DAEMON_PIDS | |
@@ -785,7 +789,8 Server stops sending after 0 length payl | |||||
785 | added 1 changesets with 1 changes to 1 files |
|
789 | added 1 changesets with 1 changes to 1 files | |
786 | transaction abort! |
|
790 | transaction abort! | |
787 | rollback completed |
|
791 | rollback completed | |
788 | abort: connection ended unexpectedly |
|
792 | abort: HTTP request error (incomplete response) | |
|
793 | (this may be an intermittent network failure; if the error persists, consider contacting the network or server operator) | |||
789 | [255] |
|
794 | [255] | |
790 |
|
795 | |||
791 | $ killdaemons.py $DAEMON_PIDS |
|
796 | $ killdaemons.py $DAEMON_PIDS |
General Comments 0
You need to be logged in to leave comments.
Login now