##// END OF EJS Templates
dispatch: protect against malicious 'hg serve --stdio' invocations (sec)...
dispatch: protect against malicious 'hg serve --stdio' invocations (sec) Some shared-ssh installations assume that 'hg serve --stdio' is a safe command to run for minimally trusted users. Unfortunately, the messy implementation of argument parsing here meant that trying to access a repo named '--debugger' would give the user a pdb prompt, thereby sidestepping any hoped-for sandboxing. Serving repositories over HTTP(S) is unaffected. We're not currently hardening any subcommands other than 'serve'. If your service exposes other commands to users with arbitrary repository names, it is imperative that you defend against repository names of '--debugger' and anything starting with '--config'. The read-only mode of hg-ssh stopped working because it provided its hook configuration to "hg serve --stdio" via --config parameter. This is banned for security reasons now. This patch switches it to directly call ui.setconfig(). If your custom hosting infrastructure relies on passing --config to "hg serve --stdio", you'll need to find a different way to get that configuration into Mercurial, either by using ui.setconfig() as hg-ssh does in this patch, or by placing an hgrc file someplace where Mercurial will read it. mitrandir@fb.com provided some extra fixes for the dispatch code and for hg-ssh in places that I overlooked.

File last commit:

r28800:544908ae default
r32050:77eaf953 4.1.3 stable
Show More
test-batching.py
180 lines | 5.5 KiB | text/x-python | PythonLexer
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 # test-batching.py - tests for transparent command batching
#
# Copyright 2011 Peter Arrenbrecht <peter@arrenbrecht.ch>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Robert Stanca
py3: use print_function in test-batching.py
r28732 from __future__ import absolute_import, print_function
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800
from mercurial import (
peer,
wireproto,
Robert Stanca
py3: use absolute_import in test-batching.py
r28731 )
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# equivalent of repo.repository
class thing(object):
def hello(self):
return "Ready."
# equivalent of localrepo.localrepository
class localthing(thing):
def foo(self, one, two=None):
if one:
return "%s and %s" % (one, two,)
return "Nope"
def bar(self, b, a):
return "%s und %s" % (b, a,)
def greet(self, name=None):
return "Hello, %s" % name
def batch(self):
'''Support for local batching.'''
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 return peer.localbatch(self)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# usage of "thing" interface
def use(it):
# Direct call to base method shared between client and server.
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(it.hello())
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# Direct calls to proxied methods. They cause individual roundtrips.
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(it.foo("Un", two="Deux"))
print(it.bar("Eins", "Zwei"))
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# Batched call to a couple of (possibly proxied) methods.
batch = it.batch()
# The calls return futures to eventually hold results.
foo = batch.foo(one="One", two="Two")
foo2 = batch.foo(None)
bar = batch.bar("Eins", "Zwei")
# We can call non-batchable proxy methods, but the break the current batch
# request and cause additional roundtrips.
greet = batch.greet(name="John Smith")
# We can also add local methods into the mix, but they break the batch too.
hello = batch.hello()
bar2 = batch.bar(b="Uno", a="Due")
# Only now are all the calls executed in sequence, with as few roundtrips
# as possible.
batch.submit()
# After the call to submit, the futures actually contain values.
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(foo.value)
print(foo2.value)
print(bar.value)
print(greet.value)
print(hello.value)
print(bar2.value)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# local usage
mylocal = localthing()
Robert Stanca
py3: use print_function in test-batching.py
r28732 print()
print("== Local")
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 use(mylocal)
# demo remoting; mimicks what wireproto and HTTP/SSH do
# shared
def escapearg(plain):
return (plain
.replace(':', '::')
.replace(',', ':,')
.replace(';', ':;')
.replace('=', ':='))
def unescapearg(escaped):
return (escaped
.replace(':=', '=')
.replace(':;', ';')
.replace(':,', ',')
.replace('::', ':'))
# server side
# equivalent of wireproto's global functions
Thomas Arendsen Hein
classes: fix class style problems found by b071cd58af50...
r14764 class server(object):
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 def __init__(self, local):
self.local = local
def _call(self, name, args):
args = dict(arg.split('=', 1) for arg in args)
return getattr(self, name)(**args)
def perform(self, req):
Robert Stanca
py3: use print_function in test-batching.py
r28732 print("REQ:", req)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 name, args = req.split('?', 1)
args = args.split('&')
vals = dict(arg.split('=', 1) for arg in args)
res = getattr(self, name)(**vals)
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(" ->", res)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 return res
def batch(self, cmds):
res = []
for pair in cmds.split(';'):
name, args = pair.split(':', 1)
vals = {}
for a in args.split(','):
if a:
n, v = a.split('=')
vals[n] = unescapearg(v)
res.append(escapearg(getattr(self, name)(**vals)))
return ';'.join(res)
def foo(self, one, two):
return mangle(self.local.foo(unmangle(one), unmangle(two)))
def bar(self, b, a):
return mangle(self.local.bar(unmangle(b), unmangle(a)))
def greet(self, name):
return mangle(self.local.greet(unmangle(name)))
myserver = server(mylocal)
# local side
# equivalent of wireproto.encode/decodelist, that is, type-specific marshalling
# here we just transform the strings a bit to check we're properly en-/decoding
def mangle(s):
return ''.join(chr(ord(c) + 1) for c in s)
def unmangle(s):
return ''.join(chr(ord(c) - 1) for c in s)
# equivalent of wireproto.wirerepository and something like http's wire format
class remotething(thing):
def __init__(self, server):
self.server = server
def _submitone(self, name, args):
req = name + '?' + '&'.join(['%s=%s' % (n, v) for n, v in args])
return self.server.perform(req)
def _submitbatch(self, cmds):
req = []
for name, args in cmds:
args = ','.join(n + '=' + escapearg(v) for n, v in args)
req.append(name + ':' + args)
req = ';'.join(req)
res = self._submitone('batch', [('cmds', req,)])
return res.split(';')
def batch(self):
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 return wireproto.remotebatch(self)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 @peer.batchable
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 def foo(self, one, two=None):
if not one:
yield "Nope", None
encargs = [('one', mangle(one),), ('two', mangle(two),)]
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 encresref = peer.future()
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 yield encargs, encresref
yield unmangle(encresref.value)
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 @peer.batchable
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 def bar(self, b, a):
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 encresref = peer.future()
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 yield [('b', mangle(b),), ('a', mangle(a),)], encresref
yield unmangle(encresref.value)
# greet is coded directly. It therefore does not support batching. If it
# does appear in a batch, the batch is split around greet, and the call to
# greet is done in its own roundtrip.
def greet(self, name=None):
return unmangle(self._submitone('greet', [('name', mangle(name),)]))
# demo remote usage
myproxy = remotething(myserver)
Robert Stanca
py3: use print_function in test-batching.py
r28732 print()
print("== Remote")
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 use(myproxy)