merge with stable
There were a handful of merge conflicts in the wire protocol code due
to significant refactoring in default. When resolving the conflicts,
I tried to produce the minimal number of changes to make the incoming
security patches work with the new code.
I will send some follow-up commits to get the security patches better
integrated into default.
--- a/.hgsigs Sun Mar 04 21:16:36 2018 -0500
+++ b/.hgsigs Tue Mar 06 14:32:14 2018 -0800
@@ -158,3 +158,5 @@
a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 0 iQJVBAABCAA/FiEEOoFVFj0OIKUw/LeGR6Z/+qNGqs4FAlohslshHGtidWxsb2NrK21lcmN1cmlhbEByaW5nd29ybGQub3JnAAoJEEemf/qjRqrO7P8P/1qGts96acEdB9BZbK/Eesalb1wUByLXZoP8j+1wWwqh/Kq/q7V4Qe0z1jw/92oZbmnLy2C8sDhWv/XKxACKv69oPrcqQix1E8M+07u88ZXqHJMSxkOmvA2Vimp9EG1qgje+qchgOVgvhEhysA96bRpEnc6V0RnBqI5UdfbKtlfBmX5mUE/qsoBZhly1FTmzV1bhYlGgNLyqtJQpcbA34wyPoywsp8DRBiHWrIzz5XNR+DJFTOe4Kqio1i5r8R4QSIM5vtTbj5pbsmtGcP2CsFC9S3xTSAU6AEJKxGpubPk3ckNj3P9zolvR7krU5Jt8LIgXSVaKLt9rPhmxCbPrLtORgXkUupJcrwzQl+oYz5bkl9kowFa959waIPYoCuuW402mOTDq/L3xwDH9AKK5rELPl3fNo+5OIDKAKRIu6zRSAzBtyGT6kkfb1NSghumP4scR7cgUmLaNibZBa8eJj92gwf+ucSGoB/dF/YHWNe0jY09LFK3nyCoftmyLzxcRk1JLGNngw8MCIuisHTskhxSm/qlX7qjunoZnA3yy9behhy/YaFt4YzYZbMTivt2gszX5ktToaDqfxWDYdIa79kp8G68rYPeybelTS74LwbK3blXPI3I1nddkW52znHYLvW6BYyi+QQ5jPZLkiOC+AF0q+c4gYmPaLVN/mpMZjjmB
27b6df1b5adbdf647cf5c6675b40575e1b197c60 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAlpmbwIQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91W4BD/4h+y7QH7FkNcueOBrmdci7w1apkPX7KuknKxf8+FmA1QDGWYATnqD6IcAk3+f4reO4n9qc0y2BGrIz/pyTSIHvJW+ORrbPCKVrXlfUgkUK3TumtRObt8B75BVBBNaJ93r1yOALpo/K8wSwRrBF+Yl6aCoFiibUEbfcfaOAHVqZXKC1ZPtLRwq5NHIw0wWB0qNoAXj+FJV1EHO7SEjj2lXqw/r0HriQMdObWLgAb6QVUq7oVMpAumUeuQtZ169qHdqYfF1OLdCnsVBcwYEz/cBLC43bvYiwFxSkbAFyl656caWiwA3PISFSzP9Co0zWU/Qf8f7dTdAdT/orzCfUq8YoXqryfRSxi+8L8/EMxankzdW73Rx5X+0539pSq+gDDtTOyNuW6+CZwa5D84b31rsd+jTx8zVm3SRHRKsoGF2EEMQkWmDbhIFjX5W1fE84Ul3umypv+lPSvCPlQpIqv2hZmcTR12sgjdBjU8z+Zcq22SHFybqiYNmWpkVUtiMvTlHMoJfi5PI6xF8D2dxV4ErG+NflqdjaXydgnbO6D3/A1FCASig0wL4jMxSeRqnRRqLihN3VaGG2QH6MLJ+Ty6YuoonKtopw9JNOZydr/XN7K5LcjX1T3+31qmnHZyBXRSejWl9XN93IDbQcnMBWHkz/cJLN0kKu4pvnV8UGUcyXfA==
d334afc585e29577f271c5eda03378736a16ca6b 0 iQJEBAABCAAuFiEEK8zhT1xnJaouqK63ucncgkqlvdUFAlpzZuUQHHJhZkBkdXJpbjQyLmNvbQAKCRC5ydyCSqW91TiDEADDD6Tn04UjgrZ36nAqOcHaG1ZT2Cm1/sbTw+6duAhf3+uKWFqi2bgcdCBkdfRH7KfEU0GNsPpiC6mzWw3PDWmGhnLJAkR+9FTBU0edK01hkNW8RelDTL5J9IzIGwrP4KFfcUue6yrxU8GnSxnf5Vy/N5ZZzLV/P3hdBte5We9PD5KHPAwTzzcZ9Wiog700rFDDChyFq7hNQ3H0GpknF6+Ck5XmJ3DOqt1MFHk9V4Z/ASU59cQXKOeaMChlBpTb1gIIWjOE99v5aY06dc1WlwttuHtCZvZgtAduRAB6XYWyniS/7nXBv0MXD3EWbpH1pkOaWUxw217HpNP4g9Yo3u/i8UW+NkSJOeXtC1CFjWmUNj138IhS1pogaiPPnIs+H6eOJsmnGhN2KbOMjA5Dn9vSTi6s/98TarfUSiwxA4L7fJy5qowFETftuBO0fJpbB8+ZtpnjNp0MMKed27OUSv69i6BmLrP+eqk+MVO6PovvIySlWAP9/REM/I5/mFkqoI+ruT4a9osNGDZ4Jqb382b7EmpEMDdgb7+ezsybgDfizuaTs/LBae7h79o1m30DxZ/EZ5C+2LY8twbGSORvZN4ViMVhIhWBTlOE/iVBOj807Y2OaUURcuLfHRmaCcfF1uIzg0uNB/aM/WSE0+AXh2IX+mipoTS3eh/V2EKldBHcOQ==
+369aadf7a3264b03c8b09efce715bc41e6ab4a9b 0 iQJVBAABCAA/FiEEOoFVFj0OIKUw/LeGR6Z/+qNGqs4FAlqe5w8hHGtidWxsb2NrK21lcmN1cmlhbEByaW5nd29ybGQub3JnAAoJEEemf/qjRqrO1lUQAK6+S26rE3AMt6667ClT+ubPl+nNMRkWJXa8EyPplBUGTPdMheViOe+28dCsveJxqUF7A4TMLMA/eIj4cRIwmVbBaivfQKnG5GMZ+9N6j6oqE/OAJujdHzzZ3+o9KJGtRgJP2tzdY/6qkXwL3WN6KULz7pSkrKZLOiNfj4k2bf3bXeB7d3N5erxJYlhddlPBlHXImRkWiPR/bdaAaYJq+EEWCbia6MWXlSAqEjIgQi+ytuh/9Z+QSsJCsECDRqEExZClqHGkCLYhST99NqqdYCGJzAFMgh+xWxZxI0LO08pJxYctHGoHm+vvRVMfmdbxEydEy01H6jX+1e7Yq44bovIiIOkaXCTSuEBol+R5aPKJhgvqgZ5IlcTLoIYQBE3MZMKZ89NWy3TvgcNkQiOPCCkKs1+DukXKqTt62zOTxfa6mIZDCXdGai6vZBJ5b0yeEd3HV96yHb9dFlS5w1cG7prIBRv5BkqEaFbRMGZGV31Ri7BuVu0O68Pfdq+R+4A1YLdJ0H5DySe2dGlwE2DMKhdtVu1bie4UWHK10TphmqhBk6B9Ew2+tASCU7iczAqRzyzMLBTHIfCYO2R+5Yuh0CApt47KV23OcLje9nORyE2yaDTbVUPiXzdOnbRaCQf7eW5/1y/LLjG6OwtuETTcHKh7ruko+u7rFL96a4DNlNdk
+8bba684efde7f45add05f737952093bb2aa07155 0 iQJVBAABCAA/FiEEOoFVFj0OIKUw/LeGR6Z/+qNGqs4FAlqe6dkhHGtidWxsb2NrK21lcmN1cmlhbEByaW5nd29ybGQub3JnAAoJEEemf/qjRqrOJmIQALUVCoWUFYYaRxGH4OpmIQ2o1JrMefvarFhaPY1r3+G87sjXgw15uobEQDtoybTUYbcdSxJQT1KE1FOm3wU0VyN6PY9c1PMEAVgJlve0eDiXNNlBsoYMXnpq1HidZknkjpXgUPdE/LElxpJJRlJQZlS29bkGmEDZQBoOvlcZoBRDSYcbM07wn7d+1gmJkcHViDBMAbSrudfO0OYzDC1BjtGyKm7Mes2WB1yFYw+ySa8hF/xPKEDvoZINOE5n3PBJiCvPuTw3PqsHvWgKOA1Obx9fATlxj7EHBLfKBTNfpUwPMRSH1cmA+qUS9mRDrdLvrThwalr6D3r2RJ2ntOipcZpKMmxARRV+VUAI1K6H0/Ws3XAxENqhF7RgRruJFVq8G8EcHJLZEoVHsR+VOnd/pzgkFKS+tIsYYRcMpL0DdMF8pV3xrEFahgRhaEZOh4jsG3Z+sGLVFFl7DdMqeGs6m/TwDrvfuYtGczfGRB0wqu8KOwhR1BjNJKcr4lk35GKwSXmI1vk6Z1gAm0e13995lqbCJwkuOKynQlHWVOR6hu3ypvAgV/zXLF5t8HHtL48sOJ8a33THuJT4whbXSIb9BQXu/NQnNhK8G3Kly5UN88vL4a3sZi/Y86h4R2fKOSib/txJ3ydLbMeS8LlJMqeF/hrBanVF0r15NZ2CdmL1Qxim
--- a/.hgtags Sun Mar 04 21:16:36 2018 -0500
+++ b/.hgtags Tue Mar 06 14:32:14 2018 -0800
@@ -171,3 +171,5 @@
a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
d334afc585e29577f271c5eda03378736a16ca6b 4.5
+369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
+8bba684efde7f45add05f737952093bb2aa07155 4.5.2
--- a/hgext/largefiles/uisetup.py Sun Mar 04 21:16:36 2018 -0500
+++ b/hgext/largefiles/uisetup.py Tue Mar 06 14:32:14 2018 -0800
@@ -12,7 +12,6 @@
from mercurial.i18n import _
from mercurial.hgweb import (
- hgweb_mod,
webcommands,
)
@@ -175,9 +174,10 @@
# make putlfile behave the same as push and {get,stat}lfile behave
# the same as pull w.r.t. permissions checks
- hgweb_mod.perms['putlfile'] = 'push'
- hgweb_mod.perms['getlfile'] = 'pull'
- hgweb_mod.perms['statlfile'] = 'pull'
+ wireproto.permissions['putlfile'] = 'push'
+ wireproto.permissions['getlfile'] = 'pull'
+ wireproto.permissions['statlfile'] = 'pull'
+ wireproto.permissions['lheads'] = 'pull'
extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath)
--- a/mercurial/changegroup.py Sun Mar 04 21:16:36 2018 -0500
+++ b/mercurial/changegroup.py Tue Mar 06 14:32:14 2018 -0800
@@ -774,6 +774,8 @@
progress(msgbundling, None)
def deltaparent(self, revlog, rev, p1, p2, prev):
+ if not revlog.candelta(prev, rev):
+ raise error.ProgrammingError('cg1 should not be used in this case')
return prev
def revchunk(self, revlog, rev, prev, linknode):
@@ -833,16 +835,19 @@
# expensive. The revlog caches should have prev cached, meaning
# less CPU for changegroup generation. There is likely room to add
# a flag and/or config option to control this behavior.
- return prev
+ base = prev
elif dp == nullrev:
# revlog is configured to use full snapshot for a reason,
# stick to full snapshot.
- return nullrev
+ base = nullrev
elif dp not in (p1, p2, prev):
# Pick prev when we can't be sure remote has the base revision.
return prev
else:
- return dp
+ base = dp
+ if base != nullrev and not revlog.candelta(base, rev):
+ base = nullrev
+ return base
def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags):
# Do nothing with flags, it is implicitly 0 in cg1 and cg2
--- a/mercurial/hgweb/hgweb_mod.py Sun Mar 04 21:16:36 2018 -0500
+++ b/mercurial/hgweb/hgweb_mod.py Tue Mar 06 14:32:14 2018 -0800
@@ -37,6 +37,7 @@
templater,
ui as uimod,
util,
+ wireproto,
wireprotoserver,
)
@@ -46,15 +47,8 @@
wsgicgi,
)
-perms = {
- 'changegroup': 'pull',
- 'changegroupsubset': 'pull',
- 'getbundle': 'pull',
- 'stream_out': 'pull',
- 'listkeys': 'pull',
- 'unbundle': 'push',
- 'pushkey': 'push',
-}
+# Aliased for API compatibility.
+perms = wireproto.permissions
archivespecs = util.sortdict((
('zip', ('application/zip', 'zip', '.zip', None)),
@@ -367,13 +361,21 @@
try:
if query:
raise ErrorResponse(HTTP_NOT_FOUND)
- if cmd in perms:
- self.check_perm(rctx, req, perms[cmd])
+
+ # TODO fold this into parsehttprequest
+ req.checkperm = lambda op: self.check_perm(rctx, req, op)
+ protohandler['proto'].checkperm = req.checkperm
+
+ # Assume commands with no defined permissions are writes /
+ # for pushes. This is the safest from a security perspective
+ # because it doesn't allow commands with undefined semantics
+ # from bypassing permissions checks.
+ req.checkperm(perms.get(cmd, 'push'))
+
+ return protohandler['dispatch']()
except ErrorResponse as inst:
return protohandler['handleerror'](inst)
- return protohandler['dispatch']()
-
# translate user-visible url structure to internal structure
args = query.split('/', 2)
--- a/mercurial/revlog.py Sun Mar 04 21:16:36 2018 -0500
+++ b/mercurial/revlog.py Tue Mar 06 14:32:14 2018 -0800
@@ -77,6 +77,8 @@
REVIDX_EXTSTORED,
]
REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER)
+# bitmark for flags that could cause rawdata content change
+REVIDX_RAWTEXT_CHANGING_FLAGS = REVIDX_ISCENSORED | REVIDX_EXTSTORED
# max size of revlog with inline data
_maxinline = 131072
@@ -96,7 +98,8 @@
"""Register a flag processor on a revision data flag.
Invariant:
- - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER.
+ - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER,
+ and REVIDX_RAWTEXT_CHANGING_FLAGS if they can alter rawtext.
- Only one flag processor can be registered on a specific flag.
- flagprocessors must be 3-tuples of functions (read, write, raw) with the
following signatures:
@@ -333,7 +336,9 @@
len(delta) - hlen):
btext[0] = delta[hlen:]
else:
- basetext = revlog.revision(baserev, _df=fh, raw=True)
+ # deltabase is rawtext before changed by flag processors, which is
+ # equivalent to non-raw text
+ basetext = revlog.revision(baserev, _df=fh, raw=False)
btext[0] = mdiff.patch(basetext, delta)
try:
@@ -404,6 +409,9 @@
for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
nominateddeltas = []
for candidaterev in candidaterevs:
+ # no delta for rawtext-changing revs (see "candelta" for why)
+ if revlog.flags(candidaterev) & REVIDX_RAWTEXT_CHANGING_FLAGS:
+ continue
candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
nominateddeltas.append(candidatedelta)
@@ -738,6 +746,18 @@
except KeyError:
return False
+ def candelta(self, baserev, rev):
+ """whether two revisions (baserev, rev) can be delta-ed or not"""
+ # Disable delta if either rev requires a content-changing flag
+ # processor (ex. LFS). This is because such flag processor can alter
+ # the rawtext content that the delta will be based on, and two clients
+ # could have a same revlog node with different flags (i.e. different
+ # rawtext contents) and the delta could be incompatible.
+ if ((self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS)
+ or (self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS)):
+ return False
+ return True
+
def clearcaches(self):
self._cache = None
self._chainbasecache.clear()
@@ -2078,7 +2098,10 @@
# full versions are inserted when the needed deltas
# become comparable to the uncompressed text
if rawtext is None:
- textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
+ # need rawtext size, before changed by flag processors, which is
+ # the non-raw size. use revlog explicitly to avoid filelog's extra
+ # logic that might remove metadata size.
+ textlen = mdiff.patchedsize(revlog.size(self, cachedelta[0]),
cachedelta[1])
else:
textlen = len(rawtext)
@@ -2087,7 +2110,14 @@
deltacomputer = _deltacomputer(self)
revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags)
- deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
+
+ # no delta for flag processor revision (see "candelta" for why)
+ # not calling candelta since only one revision needs test, also to
+ # avoid overhead fetching flags again.
+ if flags & REVIDX_RAWTEXT_CHANGING_FLAGS:
+ deltainfo = None
+ else:
+ deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
if deltainfo is not None:
base = deltainfo.base
--- a/mercurial/wireproto.py Sun Mar 04 21:16:36 2018 -0500
+++ b/mercurial/wireproto.py Tue Mar 06 14:32:14 2018 -0800
@@ -672,6 +672,11 @@
commands = commanddict()
+# Maps wire protocol name to operation type. This is used for permissions
+# checking. All defined @wireiprotocommand should have an entry in this
+# dict.
+permissions = {}
+
def wireprotocommand(name, args='', transportpolicy=POLICY_ALL):
"""Decorator to declare a wire protocol command.
@@ -701,6 +706,8 @@
return func
return register
+# TODO define a more appropriate permissions type to use for this.
+permissions['batch'] = 'pull'
@wireprotocommand('batch', 'cmds *')
def batch(repo, proto, cmds, others):
repo = repo.filtered("served")
@@ -713,6 +720,17 @@
n, v = a.split('=')
vals[unescapearg(n)] = unescapearg(v)
func, spec = commands[op]
+
+ # If the protocol supports permissions checking, perform that
+ # checking on each batched command.
+ # TODO formalize permission checking as part of protocol interface.
+ if util.safehasattr(proto, 'checkperm'):
+ # Assume commands with no defined permissions are writes / for
+ # pushes. This is the safest from a security perspective because
+ # it doesn't allow commands with undefined semantics from
+ # bypassing permissions checks.
+ proto.checkperm(permissions.get(op, 'push'))
+
if spec:
keys = spec.split()
data = {}
@@ -740,6 +758,7 @@
return bytesresponse(';'.join(res))
+permissions['between'] = 'pull'
@wireprotocommand('between', 'pairs', transportpolicy=POLICY_V1_ONLY)
def between(repo, proto, pairs):
pairs = [decodelist(p, '-') for p in pairs.split(" ")]
@@ -749,6 +768,7 @@
return bytesresponse(''.join(r))
+permissions['branchmap'] = 'pull'
@wireprotocommand('branchmap')
def branchmap(repo, proto):
branchmap = repo.branchmap()
@@ -760,6 +780,7 @@
return bytesresponse('\n'.join(heads))
+permissions['branches'] = 'pull'
@wireprotocommand('branches', 'nodes', transportpolicy=POLICY_V1_ONLY)
def branches(repo, proto, nodes):
nodes = decodelist(nodes)
@@ -769,6 +790,7 @@
return bytesresponse(''.join(r))
+permissions['clonebundles'] = 'pull'
@wireprotocommand('clonebundles', '')
def clonebundles(repo, proto):
"""Server command for returning info for available bundles to seed clones.
@@ -821,10 +843,12 @@
# If you are writing an extension and consider wrapping this function. Wrap
# `_capabilities` instead.
+permissions['capabilities'] = 'pull'
@wireprotocommand('capabilities')
def capabilities(repo, proto):
return bytesresponse(' '.join(_capabilities(repo, proto)))
+permissions['changegroup'] = 'pull'
@wireprotocommand('changegroup', 'roots', transportpolicy=POLICY_V1_ONLY)
def changegroup(repo, proto, roots):
nodes = decodelist(roots)
@@ -834,6 +858,7 @@
gen = iter(lambda: cg.read(32768), '')
return streamres(gen=gen)
+permissions['changegroupsubset'] = 'pull'
@wireprotocommand('changegroupsubset', 'bases heads',
transportpolicy=POLICY_V1_ONLY)
def changegroupsubset(repo, proto, bases, heads):
@@ -845,6 +870,7 @@
gen = iter(lambda: cg.read(32768), '')
return streamres(gen=gen)
+permissions['debugwireargs'] = 'pull'
@wireprotocommand('debugwireargs', 'one two *')
def debugwireargs(repo, proto, one, two, others):
# only accept optional args from the known set
@@ -852,6 +878,7 @@
return bytesresponse(repo.debugwireargs(one, two,
**pycompat.strkwargs(opts)))
+permissions['getbundle'] = 'pull'
@wireprotocommand('getbundle', '*')
def getbundle(repo, proto, others):
opts = options('getbundle', gboptsmap.keys(), others)
@@ -918,11 +945,13 @@
return streamres(gen=chunks, prefer_uncompressed=not prefercompressed)
+permissions['heads'] = 'pull'
@wireprotocommand('heads')
def heads(repo, proto):
h = repo.heads()
return bytesresponse(encodelist(h) + '\n')
+permissions['hello'] = 'pull'
@wireprotocommand('hello')
def hello(repo, proto):
"""Called as part of SSH handshake to obtain server info.
@@ -938,11 +967,13 @@
caps = capabilities(repo, proto).data
return bytesresponse('capabilities: %s\n' % caps)
+permissions['listkeys'] = 'pull'
@wireprotocommand('listkeys', 'namespace')
def listkeys(repo, proto, namespace):
d = sorted(repo.listkeys(encoding.tolocal(namespace)).items())
return bytesresponse(pushkeymod.encodekeys(d))
+permissions['lookup'] = 'pull'
@wireprotocommand('lookup', 'key')
def lookup(repo, proto, key):
try:
@@ -955,11 +986,13 @@
success = 0
return bytesresponse('%d %s\n' % (success, r))
+permissions['known'] = 'pull'
@wireprotocommand('known', 'nodes *')
def known(repo, proto, nodes, others):
v = ''.join(b and '1' or '0' for b in repo.known(decodelist(nodes)))
return bytesresponse(v)
+permissions['pushkey'] = 'push'
@wireprotocommand('pushkey', 'namespace key old new')
def pushkey(repo, proto, namespace, key, old, new):
# compatibility with pre-1.8 clients which were accidentally
@@ -981,6 +1014,7 @@
output = output.getvalue() if output else ''
return bytesresponse('%d\n%s' % (int(r), output))
+permissions['stream_out'] = 'pull'
@wireprotocommand('stream_out')
def stream(repo, proto):
'''If the server supports streaming clone, it advertises the "stream"
@@ -989,6 +1023,7 @@
'''
return streamres_legacy(streamclone.generatev1wireproto(repo))
+permissions['unbundle'] = 'push'
@wireprotocommand('unbundle', 'heads')
def unbundle(repo, proto, heads):
their_heads = decodelist(heads)
--- a/tests/drawdag.py Sun Mar 04 21:16:36 2018 -0500
+++ b/tests/drawdag.py Tue Mar 06 14:32:14 2018 -0800
@@ -371,7 +371,8 @@
comments = list(_getcomments(text))
filere = re.compile(br'^(\w+)/([\w/]+)\s*=\s*(.*)$', re.M)
for name, path, content in filere.findall(b'\n'.join(comments)):
- files[name][path] = content.replace(br'\n', b'\n')
+ content = content.replace(br'\n', b'\n').replace(br'\1', b'\1')
+ files[name][path] = content
committed = {None: node.nullid} # {name: node}
--- a/tests/test-annotate.t Sun Mar 04 21:16:36 2018 -0500
+++ b/tests/test-annotate.t Tue Mar 06 14:32:14 2018 -0800
@@ -903,9 +903,15 @@
$ hg init repo-cr
$ cd repo-cr
- $ substcr() {
- > sed 's/\r/[CR]/g'
- > }
+ $ cat <<'EOF' >> "$TESTTMP/substcr.py"
+ > import sys
+ > from mercurial import util
+ > util.setbinary(sys.stdin)
+ > util.setbinary(sys.stdout)
+ > stdin = getattr(sys.stdin, 'buffer', sys.stdin)
+ > stdout = getattr(sys.stdout, 'buffer', sys.stdout)
+ > stdout.write(stdin.read().replace(b'\r', b'[CR]'))
+ > EOF
>>> with open('a', 'wb') as f:
... f.write(b'0a\r0b\r\n0c\r0d\r\n0e\n0f\n0g')
@@ -914,13 +920,13 @@
... f.write(b'0a\r0b\r\n1c\r1d\r\n0e\n1f\n0g')
$ hg ci -m1
- $ hg annotate -r0 a | substcr
+ $ hg annotate -r0 a | $PYTHON "$TESTTMP/substcr.py"
0: 0a[CR]0b[CR]
0: 0c[CR]0d[CR]
0: 0e
0: 0f
0: 0g
- $ hg annotate -r1 a | substcr
+ $ hg annotate -r1 a | $PYTHON "$TESTTMP/substcr.py"
0: 0a[CR]0b[CR]
1: 1c[CR]1d[CR]
0: 0e
--- a/tests/test-http-bundle1.t Sun Mar 04 21:16:36 2018 -0500
+++ b/tests/test-http-bundle1.t Tue Mar 06 14:32:14 2018 -0800
@@ -260,60 +260,52 @@
$ hg rollback -q
$ sed 's/.*] "/"/' < ../access.log
- "GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=stream_out HTTP/1.1" 401 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
+ "GET /?cmd=capabilities HTTP/1.1" 403 -
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-http-permissions.t Tue Mar 06 14:32:14 2018 -0800
@@ -0,0 +1,1502 @@
+#require killdaemons
+
+ $ cat > fakeremoteuser.py << EOF
+ > import os
+ > from mercurial.hgweb import hgweb_mod
+ > from mercurial import wireproto
+ > class testenvhgweb(hgweb_mod.hgweb):
+ > def __call__(self, env, respond):
+ > # Allow REMOTE_USER to define authenticated user.
+ > if r'REMOTE_USER' in os.environ:
+ > env[r'REMOTE_USER'] = os.environ[r'REMOTE_USER']
+ > # Allow REQUEST_METHOD to override HTTP method
+ > if r'REQUEST_METHOD' in os.environ:
+ > env[r'REQUEST_METHOD'] = os.environ[r'REQUEST_METHOD']
+ > return super(testenvhgweb, self).__call__(env, respond)
+ > hgweb_mod.hgweb = testenvhgweb
+ >
+ > @wireproto.wireprotocommand('customreadnoperm')
+ > def customread(repo, proto):
+ > return b'read-only command no defined permissions\n'
+ > @wireproto.wireprotocommand('customwritenoperm')
+ > def customwritenoperm(repo, proto):
+ > return b'write command no defined permissions\n'
+ > wireproto.permissions['customreadwithperm'] = 'pull'
+ > @wireproto.wireprotocommand('customreadwithperm')
+ > def customreadwithperm(repo, proto):
+ > return b'read-only command w/ defined permissions\n'
+ > wireproto.permissions['customwritewithperm'] = 'push'
+ > @wireproto.wireprotocommand('customwritewithperm')
+ > def customwritewithperm(repo, proto):
+ > return b'write command w/ defined permissions\n'
+ > EOF
+
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > fakeremoteuser = $TESTTMP/fakeremoteuser.py
+ > strip =
+ > EOF
+
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+ $ cd ..
+ $ hg clone test test2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd test2
+ $ echo a >> a
+ $ hg ci -mb
+ $ hg book bm -r 0
+ $ cd ../test
+
+web.deny_read=* prevents access to wire protocol for all users
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > deny_read = *
+ > EOF
+
+ $ hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=stream_out'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.deny_read=* with REMOTE_USER set still locks out clients
+
+ $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=stream_out'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.deny_read=<user> denies access to unauthenticated user
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > deny_read = baduser1,baduser2
+ > EOF
+
+ $ hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.deny_read=<user> denies access to users in deny list
+
+ $ REMOTE_USER=baduser2 hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.deny_read=<user> allows access to authenticated users not in list
+
+ $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 200 Script output follows
+
+ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
+ publishing True (no-eol)
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 200 Script output follows
+
+ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
+ publishing True (no-eol)
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 200 Script output follows
+
+ read-only command w/ defined permissions
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+
+ $ killdaemons.py
+
+web.allow_read=* allows reads for unauthenticated users
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > allow_read = *
+ > EOF
+
+ $ hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 200 Script output follows
+
+ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
+ publishing True (no-eol)
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 200 Script output follows
+
+ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
+ publishing True (no-eol)
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 200 Script output follows
+
+ read-only command w/ defined permissions
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+
+ $ killdaemons.py
+
+web.allow_read=* allows read for authenticated user
+
+ $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 200 Script output follows
+
+ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
+ publishing True (no-eol)
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 200 Script output follows
+
+ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
+ publishing True (no-eol)
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 200 Script output follows
+
+ read-only command w/ defined permissions
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+
+ $ killdaemons.py
+
+web.allow_read=<user> does not allow unauthenticated users to read
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > allow_read = gooduser
+ > EOF
+
+ $ hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.allow_read=<user> does not allow user not in list to read
+
+ $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.allow_read=<user> allows read from user in list
+
+ $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 200 Script output follows
+
+ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
+ publishing True (no-eol)
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 200 Script output follows
+
+ cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b 1
+ publishing True (no-eol)
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 200 Script output follows
+
+ read-only command w/ defined permissions
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+
+ $ killdaemons.py
+
+web.deny_read takes precedence over web.allow_read
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > allow_read = baduser
+ > deny_read = baduser
+ > EOF
+
+ $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.allow-pull=false denies read access to repo
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > allow-pull = false
+ > EOF
+
+ $ hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities'
+ 401 pull not authorized
+
+ 0
+ pull not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
+ 401 pull not authorized
+
+ 0
+ pull not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
+ 401 pull not authorized
+
+ 0
+ pull not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 401 pull not authorized
+
+ 0
+ pull not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ hg --cwd ../test2 pull http://localhost:$HGPORT/
+ pulling from http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+Attempting a write command with HTTP GET fails
+
+ $ cat > .hg/hgrc <<EOF
+ > EOF
+
+ $ REQUEST_METHOD=GET hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+ $ hg bookmark -d bm
+ abort: bookmark 'bm' does not exist
+ [255]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ killdaemons.py
+
+Attempting a write command with an unknown HTTP verb fails
+
+ $ REQUEST_METHOD=someverb hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+ $ hg bookmark -d bm
+ abort: bookmark 'bm' does not exist
+ [255]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 405 push requires POST request
+
+ 0
+ push requires POST request
+ [1]
+
+ $ killdaemons.py
+
+Pushing on a plaintext channel is disabled by default
+
+ $ cat > .hg/hgrc <<EOF
+ > EOF
+
+ $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 403 ssl required
+
+ 0
+ ssl required
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 403 ssl required
+
+ 0
+ ssl required
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 403 ssl required
+
+ 0
+ ssl required
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 403 ssl required
+
+ 0
+ ssl required
+ [1]
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ abort: HTTP Error 403: ssl required
+ [255]
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: HTTP Error 403: ssl required
+ [255]
+
+ $ killdaemons.py
+
+web.deny_push=* denies pushing to unauthenticated users
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > push_ssl = false
+ > deny_push = *
+ > EOF
+
+ $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ abort: authorization failed
+ [255]
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.deny_push=* denies pushing to authenticated users
+
+ $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ abort: authorization failed
+ [255]
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.deny_push=<user> denies pushing to user in list
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > push_ssl = false
+ > deny_push = baduser
+ > EOF
+
+ $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ abort: authorization failed
+ [255]
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.deny_push=<user> denies pushing to user not in list because allow-push isn't set
+
+ $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ abort: authorization failed
+ [255]
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.allow-push=* allows pushes from unauthenticated users
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > push_ssl = false
+ > allow-push = *
+ > EOF
+
+ $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 200 Script output follows
+
+ 1
+
+ $ hg bookmarks
+ bm 0:cb9a9f314b8b
+ $ hg book -d bm
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 200 Script output follows
+
+ write command no defined permissions
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 200 Script output follows
+
+ write command w/ defined permissions
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ exporting bookmark bm
+ [1]
+
+ $ hg book -d bm
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+
+ $ hg strip -r 1:
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
+
+ $ killdaemons.py
+
+web.allow-push=* allows pushes from authenticated users
+
+ $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 200 Script output follows
+
+ 1
+
+ $ hg bookmarks
+ bm 0:cb9a9f314b8b
+ $ hg book -d bm
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 200 Script output follows
+
+ write command no defined permissions
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 200 Script output follows
+
+ write command w/ defined permissions
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ exporting bookmark bm
+ [1]
+
+ $ hg book -d bm
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+
+ $ hg strip -r 1:
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
+
+ $ killdaemons.py
+
+web.allow-push=<user> denies push to user not in list
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > push_ssl = false
+ > allow-push = gooduser
+ > EOF
+
+ $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ abort: authorization failed
+ [255]
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.allow-push=<user> allows push from user in list
+
+ $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 200 Script output follows
+
+ 1
+
+ $ hg bookmarks
+ bm 0:cb9a9f314b8b
+ $ hg book -d bm
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 200 Script output follows
+
+ 1
+
+ $ hg bookmarks
+ bm 0:cb9a9f314b8b
+ $ hg book -d bm
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 200 Script output follows
+
+ write command no defined permissions
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 200 Script output follows
+
+ write command w/ defined permissions
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ exporting bookmark bm
+ [1]
+
+ $ hg book -d bm
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+
+ $ hg strip -r 1:
+ saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
+
+ $ killdaemons.py
+
+web.deny_push takes precedence over web.allow_push
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > push_ssl = false
+ > allow-push = someuser
+ > deny_push = someuser
+ > EOF
+
+ $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 push not authorized
+
+ 0
+ push not authorized
+ [1]
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ abort: authorization failed
+ [255]
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
+
+web.allow-push has no effect if web.deny_read is set
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > push_ssl = false
+ > allow-push = *
+ > deny_read = *
+ > EOF
+
+ $ REQUEST_METHOD=POST REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ hg bookmarks
+ no bookmarks set
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadnoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customreadwithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritenoperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+ $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=customwritewithperm'
+ 401 read not authorized
+
+ 0
+ read not authorized
+ [1]
+
+Reset server to remove REQUEST_METHOD hack to test hg client
+
+ $ killdaemons.py
+ $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
+ $ cat hg.pid > $DAEMON_PIDS
+
+ $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ hg --cwd ../test2 push http://localhost:$HGPORT/
+ pushing to http://localhost:$HGPORT/
+ abort: authorization failed
+ [255]
+
+ $ killdaemons.py
--- a/tests/test-http.t Sun Mar 04 21:16:36 2018 -0500
+++ b/tests/test-http.t Tue Mar 06 14:32:14 2018 -0800
@@ -254,6 +254,7 @@
http auth: user user, password ****
sending capabilities command
devel-peer-request: GET http://localhost:$HGPORT2/?cmd=capabilities
+ http auth: user user, password ****
devel-peer-request: finished in *.???? seconds (200) (glob)
query 1; heads
sending batch command
@@ -270,7 +271,6 @@
devel-peer-request: Vary X-HgArg-1,X-HgProto-1
devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$
devel-peer-request: 16 bytes of commands arguments in headers
- http auth: user user, password ****
devel-peer-request: finished in *.???? seconds (200) (glob)
received listkey for "phases": 58 bytes
checking for updated bookmarks
@@ -340,57 +340,49 @@
$ hg rollback -q
$ sed 's/.*] "/"/' < ../access.log
- "GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=stream_out HTTP/1.1" 401 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=0&common=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=getbundle HTTP/1.1" 401 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
+ "GET /?cmd=capabilities HTTP/1.1" 403 -
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
@@ -398,9 +390,9 @@
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365* (glob)
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
+ "GET /?cmd=capabilities HTTP/1.1" 401 -
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
"GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$
--- a/tests/test-largefiles-wireproto.t Sun Mar 04 21:16:36 2018 -0500
+++ b/tests/test-largefiles-wireproto.t Tue Mar 06 14:32:14 2018 -0800
@@ -444,11 +444,11 @@
> EOF
$ hg clone --config ui.interactive=true --config extensions.getpass=get_pass.py \
> http://user@localhost:$HGPORT credentialclone
- requesting all changes
http authorization required for http://localhost:$HGPORT/
realm: mercurial
user: user
- password: adding changesets
+ password: requesting all changes
+ adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-lfs-bundle.t Tue Mar 06 14:32:14 2018 -0800
@@ -0,0 +1,97 @@
+In this test, we want to test LFS bundle application on both LFS and non-LFS
+repos.
+
+To make it more interesting, the file revisions will contain hg filelog
+metadata ('\1\n'). The bundle will have 1 file revision overlapping with the
+destination repo.
+
+# rev 1 2 3
+# repo: yes yes no
+# bundle: no (base) yes yes (deltabase: 2 if possible)
+
+It is interesting because rev 2 could have been stored as LFS in the repo, and
+non-LFS in the bundle; or vice-versa.
+
+Init
+
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > lfs=
+ > drawdag=$TESTDIR/drawdag.py
+ > [lfs]
+ > url=file:$TESTTMP/lfs-remote
+ > EOF
+
+Helper functions
+
+ $ commitxy() {
+ > hg debugdrawdag "$@" <<'EOS'
+ > Y # Y/X=\1\nAAAA\nE\nF
+ > | # Y/Y=\1\nAAAA\nG\nH
+ > X # X/X=\1\nAAAA\nC\n
+ > # X/Y=\1\nAAAA\nD\n
+ > EOS
+ > }
+
+ $ commitz() {
+ > hg debugdrawdag "$@" <<'EOS'
+ > Z # Z/X=\1\nAAAA\nI\n
+ > | # Z/Y=\1\nAAAA\nJ\n
+ > | # Z/Z=\1\nZ
+ > Y
+ > EOS
+ > }
+
+ $ enablelfs() {
+ > cat >> .hg/hgrc <<EOF
+ > [lfs]
+ > track=all()
+ > EOF
+ > }
+
+Generate bundles
+
+ $ for i in normal lfs; do
+ > NAME=src-$i
+ > hg init $TESTTMP/$NAME
+ > cd $TESTTMP/$NAME
+ > [ $i = lfs ] && enablelfs
+ > commitxy
+ > commitz
+ > hg bundle -q --base X -r Y+Z $TESTTMP/$NAME.bundle
+ > SRCNAMES="$SRCNAMES $NAME"
+ > done
+
+Prepare destination repos
+
+ $ for i in normal lfs; do
+ > NAME=dst-$i
+ > hg init $TESTTMP/$NAME
+ > cd $TESTTMP/$NAME
+ > [ $i = lfs ] && enablelfs
+ > commitxy
+ > DSTNAMES="$DSTNAMES $NAME"
+ > done
+
+Apply bundles
+
+ $ for i in $SRCNAMES; do
+ > for j in $DSTNAMES; do
+ > echo ---- Applying $i.bundle to $j ----
+ > cp -R $TESTTMP/$j $TESTTMP/tmp-$i-$j
+ > cd $TESTTMP/tmp-$i-$j
+ > if hg unbundle $TESTTMP/$i.bundle -q 2>/dev/null; then
+ > hg verify -q && echo OK
+ > else
+ > echo CRASHED
+ > fi
+ > done
+ > done
+ ---- Applying src-normal.bundle to dst-normal ----
+ OK
+ ---- Applying src-normal.bundle to dst-lfs ----
+ OK
+ ---- Applying src-lfs.bundle to dst-normal ----
+ OK
+ ---- Applying src-lfs.bundle to dst-lfs ----
+ OK
--- a/tests/test-lfs.t Sun Mar 04 21:16:36 2018 -0500
+++ b/tests/test-lfs.t Tue Mar 06 14:32:14 2018 -0800
@@ -371,7 +371,7 @@
uncompressed size of bundle content:
* (changelog) (glob)
* (manifests) (glob)
- * a (glob)
+ * a (glob)
$ hg --config extensions.strip= strip -r 2 --no-backup --force -q
$ hg -R bundle.hg log -p -T '{rev} {desc}\n' a
5 branching
--- a/tests/test-pull-http.t Sun Mar 04 21:16:36 2018 -0500
+++ b/tests/test-pull-http.t Tue Mar 06 14:32:14 2018 -0800
@@ -50,7 +50,6 @@
$ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
$ hg clone http://localhost:$HGPORT/ test4 # bundle2+
- requesting all changes
abort: authorization failed
[255]
$ hg clone http://localhost:$HGPORT/ test4 --config devel.legacy.exchange=bundle1
@@ -74,7 +73,6 @@
$ req
pulling from http://localhost:$HGPORT/
- searching for changes
abort: authorization failed
% serve errors
--- a/tests/test-push-http.t Sun Mar 04 21:16:36 2018 -0500
+++ b/tests/test-push-http.t Tue Mar 06 14:32:14 2018 -0800
@@ -307,28 +307,6 @@
$ hg --config extensions.strip= strip -r 1:
saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
-expect authorization error: all users denied
-
- $ echo '[web]' > .hg/hgrc
- $ echo 'push_ssl = false' >> .hg/hgrc
- $ echo 'deny_push = *' >> .hg/hgrc
- $ req
- pushing to http://localhost:$HGPORT/
- searching for changes
- abort: authorization failed
- % serve errors
- [255]
-
-expect authorization error: some users denied, users must be authenticated
-
- $ echo 'deny_push = unperson' >> .hg/hgrc
- $ req
- pushing to http://localhost:$HGPORT/
- searching for changes
- abort: authorization failed
- % serve errors
- [255]
-
#if bundle2
$ cat > .hg/hgrc <<EOF
--- a/tests/test-revlog-raw.py Sun Mar 04 21:16:36 2018 -0500
+++ b/tests/test-revlog-raw.py Tue Mar 06 14:32:14 2018 -0800
@@ -114,6 +114,8 @@
else:
# suboptimal deltaparent
deltaparent = min(0, parentrev)
+ if not rlog.candelta(deltaparent, r):
+ deltaparent = -1
return {'node': rlog.node(r), 'p1': pnode, 'p2': node.nullid,
'cs': rlog.node(rlog.linkrev(r)), 'flags': rlog.flags(r),
'deltabase': rlog.node(deltaparent),
@@ -151,12 +153,14 @@
for r in rlog:
p1 = rlog.node(r - 1)
p2 = node.nullid
- if r == 0:
+ if r == 0 or (rlog.flags(r) & revlog.REVIDX_EXTSTORED):
text = rlog.revision(r, raw=True)
cachedelta = None
else:
- # deltaparent is more interesting if it has the EXTSTORED flag.
- deltaparent = max([0] + [p for p in range(r - 2) if rlog.flags(p)])
+ # deltaparent cannot have EXTSTORED flag.
+ deltaparent = max([-1] +
+ [p for p in range(r)
+ if rlog.flags(p) & revlog.REVIDX_EXTSTORED == 0])
text = None
cachedelta = (deltaparent, rlog.revdiff(deltaparent, r))
flags = rlog.flags(r)
@@ -262,8 +266,9 @@
result.append((text, rawtext))
# Verify flags like isdelta, isext work as expected
- if bool(rlog.deltaparent(rev) > -1) != isdelta:
- abort('rev %d: isdelta is ineffective' % rev)
+ # isdelta can be overridden to False if this or p1 has isext set
+ if bool(rlog.deltaparent(rev) > -1) and not isdelta:
+ abort('rev %d: isdelta is unexpected' % rev)
if bool(rlog.flags(rev)) != isext:
abort('rev %d: isext is ineffective' % rev)
return result