##// END OF EJS Templates
cmdserver: protect pipe server streams against corruption caused by direct io...
Yuya Nishihara -
r23324:69f86b93 default
parent child Browse files
Show More
@@ -7,7 +7,7 b''
7
7
8 from i18n import _
8 from i18n import _
9 import struct
9 import struct
10 import os, errno, traceback, SocketServer
10 import sys, os, errno, traceback, SocketServer
11 import dispatch, encoding, util
11 import dispatch, encoding, util
12
12
13 logfile = None
13 logfile = None
@@ -248,6 +248,29 b' class server(object):'
248
248
249 return 0
249 return 0
250
250
251 def _protectio(ui):
252 """ duplicates streams and redirect original to null if ui uses stdio """
253 ui.flush()
254 newfiles = []
255 nullfd = os.open(os.devnull, os.O_RDWR)
256 for f, sysf, mode in [(ui.fin, sys.stdin, 'rb'),
257 (ui.fout, sys.stdout, 'wb')]:
258 if f is sysf:
259 newfd = os.dup(f.fileno())
260 os.dup2(nullfd, f.fileno())
261 f = os.fdopen(newfd, mode)
262 newfiles.append(f)
263 os.close(nullfd)
264 return tuple(newfiles)
265
266 def _restoreio(ui, fin, fout):
267 """ restores streams from duplicated ones """
268 ui.flush()
269 for f, uif in [(fin, ui.fin), (fout, ui.fout)]:
270 if f is not uif:
271 os.dup2(f.fileno(), uif.fileno())
272 f.close()
273
251 class pipeservice(object):
274 class pipeservice(object):
252 def __init__(self, ui, repo, opts):
275 def __init__(self, ui, repo, opts):
253 self.ui = ui
276 self.ui = ui
@@ -258,8 +281,14 b' class pipeservice(object):'
258
281
259 def run(self):
282 def run(self):
260 ui = self.ui
283 ui = self.ui
261 sv = server(ui, self.repo, ui.fin, ui.fout)
284 # redirect stdio to null device so that broken extensions or in-process
262 return sv.serve()
285 # hooks will never cause corruption of channel protocol.
286 fin, fout = _protectio(ui)
287 try:
288 sv = server(ui, self.repo, fin, fout)
289 return sv.serve()
290 finally:
291 _restoreio(ui, fin, fout)
263
292
264 class _requesthandler(SocketServer.StreamRequestHandler):
293 class _requesthandler(SocketServer.StreamRequestHandler):
265 def handle(self):
294 def handle(self):
@@ -492,6 +492,7 b' check that local configs for the cached '
492 foo
492 foo
493
493
494 $ cat <<EOF > dbgui.py
494 $ cat <<EOF > dbgui.py
495 > import os, sys
495 > from mercurial import cmdutil, commands
496 > from mercurial import cmdutil, commands
496 > cmdtable = {}
497 > cmdtable = {}
497 > command = cmdutil.command(cmdtable)
498 > command = cmdutil.command(cmdtable)
@@ -501,6 +502,14 b' check that local configs for the cached '
501 > @command("debugprompt", norepo=True)
502 > @command("debugprompt", norepo=True)
502 > def debugprompt(ui):
503 > def debugprompt(ui):
503 > ui.write("%s\\n" % ui.prompt("prompt:"))
504 > ui.write("%s\\n" % ui.prompt("prompt:"))
505 > @command("debugreadstdin", norepo=True)
506 > def debugreadstdin(ui):
507 > ui.write("read: %r\n" % sys.stdin.read(1))
508 > @command("debugwritestdout", norepo=True)
509 > def debugwritestdout(ui):
510 > os.write(1, "low-level stdout fd and\n")
511 > sys.stdout.write("stdout should be redirected to /dev/null\n")
512 > sys.stdout.flush()
504 > EOF
513 > EOF
505 $ cat <<EOF >> .hg/hgrc
514 $ cat <<EOF >> .hg/hgrc
506 > [extensions]
515 > [extensions]
@@ -518,10 +527,15 b' check that local configs for the cached '
518 ... runcommand(server, ['debugprompt', '--config',
527 ... runcommand(server, ['debugprompt', '--config',
519 ... 'ui.interactive=True'],
528 ... 'ui.interactive=True'],
520 ... input=cStringIO.StringIO('5678\n'))
529 ... input=cStringIO.StringIO('5678\n'))
530 ... runcommand(server, ['debugreadstdin'])
531 ... runcommand(server, ['debugwritestdout'])
521 *** runcommand debuggetpass --config ui.interactive=True
532 *** runcommand debuggetpass --config ui.interactive=True
522 password: 1234
533 password: 1234
523 *** runcommand debugprompt --config ui.interactive=True
534 *** runcommand debugprompt --config ui.interactive=True
524 prompt: 5678
535 prompt: 5678
536 *** runcommand debugreadstdin
537 read: ''
538 *** runcommand debugwritestdout
525
539
526
540
527 run commandserver in commandserver, which is silly but should work:
541 run commandserver in commandserver, which is silly but should work:
General Comments 0
You need to be logged in to leave comments. Login now