7d0f2b
diff -r cceaf7af4c9e hgext/largefiles/uisetup.py
7d0f2b
--- a/hgext/largefiles/uisetup.py	Sat Jun 01 17:09:41 2013 -0500
7d0f2b
+++ b/hgext/largefiles/uisetup.py	Tue Jul 03 11:25:06 2018 +0200
7d0f2b
@@ -11,7 +11,7 @@
7d0f2b
 from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \
7d0f2b
     httppeer, localrepo, merge, scmutil, sshpeer, wireproto, revset
7d0f2b
 from mercurial.i18n import _
7d0f2b
-from mercurial.hgweb import hgweb_mod, webcommands
7d0f2b
+from mercurial.hgweb import webcommands
7d0f2b
 from mercurial.subrepo import hgsubrepo
7d0f2b
 
7d0f2b
 import overrides
7d0f2b
@@ -134,9 +134,10 @@
7d0f2b
 
7d0f2b
     # make putlfile behave the same as push and {get,stat}lfile behave
7d0f2b
     # the same as pull w.r.t. permissions checks
7d0f2b
-    hgweb_mod.perms['putlfile'] = 'push'
7d0f2b
-    hgweb_mod.perms['getlfile'] = 'pull'
7d0f2b
-    hgweb_mod.perms['statlfile'] = 'pull'
7d0f2b
+    wireproto.permissions['putlfile'] = 'push'
7d0f2b
+    wireproto.permissions['getlfile'] = 'pull'
7d0f2b
+    wireproto.permissions['statlfile'] = 'pull'
7d0f2b
+    wireproto.permissions['lheads'] = 'pull'
7d0f2b
 
7d0f2b
     extensions.wrapfunction(webcommands, 'decodepath', overrides.decodepath)
7d0f2b
 
7d0f2b
diff -r cceaf7af4c9e mercurial/hgweb/hgweb_mod.py
7d0f2b
--- a/mercurial/hgweb/hgweb_mod.py	Sat Jun 01 17:09:41 2013 -0500
7d0f2b
+++ b/mercurial/hgweb/hgweb_mod.py	Tue Jul 03 11:25:06 2018 +0200
7d0f2b
@@ -7,7 +7,7 @@
7d0f2b
 # GNU General Public License version 2 or any later version.
7d0f2b
 
7d0f2b
 import os
7d0f2b
-from mercurial import ui, hg, hook, error, encoding, templater, util, repoview
7d0f2b
+from mercurial import ui, hg, hook, error, encoding, templater, util, repoview, wireproto
7d0f2b
 from mercurial.templatefilters import websub
7d0f2b
 from mercurial.i18n import _
7d0f2b
 from common import get_stat, ErrorResponse, permhooks, caching
7d0f2b
@@ -16,15 +16,8 @@
7d0f2b
 from request import wsgirequest
7d0f2b
 import webcommands, protocol, webutil, re
7d0f2b
 
7d0f2b
-perms = {
7d0f2b
-    'changegroup': 'pull',
7d0f2b
-    'changegroupsubset': 'pull',
7d0f2b
-    'getbundle': 'pull',
7d0f2b
-    'stream_out': 'pull',
7d0f2b
-    'listkeys': 'pull',
7d0f2b
-    'unbundle': 'push',
7d0f2b
-    'pushkey': 'push',
7d0f2b
-}
7d0f2b
+# Aliased for API compatibility.
7d0f2b
+perms = wireproto.permissions
7d0f2b
 
7d0f2b
 def makebreadcrumb(url, prefix=''):
7d0f2b
     '''Return a 'URL breadcrumb' list
7d0f2b
@@ -165,8 +158,13 @@
7d0f2b
             try:
7d0f2b
                 if query:
7d0f2b
                     raise ErrorResponse(HTTP_NOT_FOUND)
7d0f2b
-                if cmd in perms:
7d0f2b
-                    self.check_perm(req, perms[cmd])
7d0f2b
+
7d0f2b
+                req.checkperm = lambda op: self.check_perm(req, op)
7d0f2b
+                # Assume commands with no defined permissions are writes /
7d0f2b
+                # for pushes. This is the safest from a security perspective
7d0f2b
+                # because it doesn't allow commands with undefined semantics
7d0f2b
+                # from bypassing permissions checks.
7d0f2b
+                req.checkperm(perms.get(cmd, 'push'))
7d0f2b
                 return protocol.call(self.repo, req, cmd)
7d0f2b
             except ErrorResponse, inst:
7d0f2b
                 # A client that sends unbundle without 100-continue will
7d0f2b
diff -r cceaf7af4c9e mercurial/hgweb/protocol.py
7d0f2b
--- a/mercurial/hgweb/protocol.py	Sat Jun 01 17:09:41 2013 -0500
7d0f2b
+++ b/mercurial/hgweb/protocol.py	Tue Jul 03 11:25:06 2018 +0200
7d0f2b
@@ -17,6 +17,7 @@
7d0f2b
         self.req = req
7d0f2b
         self.response = ''
7d0f2b
         self.ui = ui
7d0f2b
+        self.checkperm = req.checkperm
7d0f2b
     def getargs(self, args):
7d0f2b
         knownargs = self._args()
7d0f2b
         data = {}
7d0f2b
diff -r cceaf7af4c9e mercurial/wireproto.py
7d0f2b
--- a/mercurial/wireproto.py	Sat Jun 01 17:09:41 2013 -0500
7d0f2b
+++ b/mercurial/wireproto.py	Tue Jul 03 11:25:06 2018 +0200
7d0f2b
@@ -11,6 +11,10 @@
7d0f2b
 import changegroup as changegroupmod
7d0f2b
 import peer, error, encoding, util, store
7d0f2b
 
7d0f2b
+# Maps wire protocol name to operation type. This is used for permissions
7d0f2b
+# checking.
7d0f2b
+permissions = {}
7d0f2b
+
7d0f2b
 # abstract batching support
7d0f2b
 
7d0f2b
 class future(object):
7d0f2b
@@ -361,6 +365,15 @@
7d0f2b
                          % (cmd, ",".join(others)))
7d0f2b
     return opts
7d0f2b
 
7d0f2b
+def wireprotocommand(name, args=''):
7d0f2b
+    """decorator for wire protocol command"""
7d0f2b
+    def register(func):
7d0f2b
+        commands[name] = (func, args)
7d0f2b
+        return func
7d0f2b
+    return register
7d0f2b
+
7d0f2b
+# TODO define a more appropriate permissions type to use for this.
7d0f2b
+permissions['batch'] = 'pull'
7d0f2b
 def batch(repo, proto, cmds, others):
7d0f2b
     repo = repo.filtered("served")
7d0f2b
     res = []
7d0f2b
@@ -372,6 +385,17 @@
7d0f2b
                 n, v = a.split('=')
7d0f2b
                 vals[n] = unescapearg(v)
7d0f2b
         func, spec = commands[op]
7d0f2b
+
7d0f2b
+        # If the protocol supports permissions checking, perform that
7d0f2b
+        # checking on each batched command.
7d0f2b
+        # TODO formalize permission checking as part of protocol interface.
7d0f2b
+        if util.safehasattr(proto, 'checkperm'):
7d0f2b
+            # Assume commands with no defined permissions are writes / for
7d0f2b
+            # pushes. This is the safest from a security perspective because
7d0f2b
+            # it doesn't allow commands with undefined semantics from
7d0f2b
+            # bypassing permissions checks.
7d0f2b
+            proto.checkperm(permissions.get(op, 'push'))
7d0f2b
+
7d0f2b
         if spec:
7d0f2b
             keys = spec.split()
7d0f2b
             data = {}
7d0f2b
@@ -392,6 +416,7 @@
7d0f2b
         res.append(escapearg(result))
7d0f2b
     return ';'.join(res)
7d0f2b
 
7d0f2b
+permissions['between'] = 'pull'
7d0f2b
 def between(repo, proto, pairs):
7d0f2b
     pairs = [decodelist(p, '-') for p in pairs.split(" ")]
7d0f2b
     r = []
7d0f2b
@@ -399,6 +424,7 @@
7d0f2b
         r.append(encodelist(b) + "\n")
7d0f2b
     return "".join(r)
7d0f2b
 
7d0f2b
+permissions['branchmap'] = 'pull'
7d0f2b
 def branchmap(repo, proto):
7d0f2b
     branchmap = repo.branchmap()
7d0f2b
     heads = []
7d0f2b
@@ -408,6 +434,7 @@
7d0f2b
         heads.append('%s %s' % (branchname, branchnodes))
7d0f2b
     return '\n'.join(heads)
7d0f2b
 
7d0f2b
+permissions['branches'] = 'pull'
7d0f2b
 def branches(repo, proto, nodes):
7d0f2b
     nodes = decodelist(nodes)
7d0f2b
     r = []
7d0f2b
@@ -415,6 +442,7 @@
7d0f2b
         r.append(encodelist(b) + "\n")
7d0f2b
     return "".join(r)
7d0f2b
 
7d0f2b
+permissions['capabilities'] = 'pull'
7d0f2b
 def capabilities(repo, proto):
7d0f2b
     caps = ('lookup changegroupsubset branchmap pushkey known getbundle '
7d0f2b
             'unbundlehash batch').split()
7d0f2b
@@ -432,22 +460,26 @@
7d0f2b
     caps.append('httpheader=1024')
7d0f2b
     return ' '.join(caps)
7d0f2b
 
7d0f2b
+permissions['changegroup'] = 'pull'
7d0f2b
 def changegroup(repo, proto, roots):
7d0f2b
     nodes = decodelist(roots)
7d0f2b
     cg = repo.changegroup(nodes, 'serve')
7d0f2b
     return streamres(proto.groupchunks(cg))
7d0f2b
 
7d0f2b
+permissions['changegroupsubset'] = 'pull'
7d0f2b
 def changegroupsubset(repo, proto, bases, heads):
7d0f2b
     bases = decodelist(bases)
7d0f2b
     heads = decodelist(heads)
7d0f2b
     cg = repo.changegroupsubset(bases, heads, 'serve')
7d0f2b
     return streamres(proto.groupchunks(cg))
7d0f2b
 
7d0f2b
+permissions['debugwireargs'] = 'pull'
7d0f2b
 def debugwireargs(repo, proto, one, two, others):
7d0f2b
     # only accept optional args from the known set
7d0f2b
     opts = options('debugwireargs', ['three', 'four'], others)
7d0f2b
     return repo.debugwireargs(one, two, **opts)
7d0f2b
 
7d0f2b
+permissions['getbundle'] = 'pull'
7d0f2b
 def getbundle(repo, proto, others):
7d0f2b
     opts = options('getbundle', ['heads', 'common'], others)
7d0f2b
     for k, v in opts.iteritems():
7d0f2b
@@ -455,10 +487,12 @@
7d0f2b
     cg = repo.getbundle('serve', **opts)
7d0f2b
     return streamres(proto.groupchunks(cg))
7d0f2b
 
7d0f2b
+permissions['heads'] = 'pull'
7d0f2b
 def heads(repo, proto):
7d0f2b
     h = repo.heads()
7d0f2b
     return encodelist(h) + "\n"
7d0f2b
 
7d0f2b
+permissions['hello'] = 'pull'
7d0f2b
 def hello(repo, proto):
7d0f2b
     '''the hello command returns a set of lines describing various
7d0f2b
     interesting things about the server, in an RFC822-like format.
7d0f2b
@@ -469,12 +503,14 @@
7d0f2b
     '''
7d0f2b
     return "capabilities: %s\n" % (capabilities(repo, proto))
7d0f2b
 
7d0f2b
+permissions['listkeys'] = 'pull'
7d0f2b
 def listkeys(repo, proto, namespace):
7d0f2b
     d = repo.listkeys(encoding.tolocal(namespace)).items()
7d0f2b
     t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v))
7d0f2b
                    for k, v in d])
7d0f2b
     return t
7d0f2b
 
7d0f2b
+permissions['lookup'] = 'pull'
7d0f2b
 def lookup(repo, proto, key):
7d0f2b
     try:
7d0f2b
         k = encoding.tolocal(key)
7d0f2b
@@ -486,9 +522,11 @@
7d0f2b
         success = 0
7d0f2b
     return "%s %s\n" % (success, r)
7d0f2b
 
7d0f2b
+permissions['known'] = 'pull'
7d0f2b
 def known(repo, proto, nodes, others):
7d0f2b
     return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
7d0f2b
 
7d0f2b
+permissions['pushkey'] = 'push'
7d0f2b
 def pushkey(repo, proto, namespace, key, old, new):
7d0f2b
     # compatibility with pre-1.8 clients which were accidentally
7d0f2b
     # sending raw binary nodes rather than utf-8-encoded hex
7d0f2b
@@ -523,6 +561,7 @@
7d0f2b
 def _allowstream(ui):
7d0f2b
     return ui.configbool('server', 'uncompressed', True, untrusted=True)
7d0f2b
 
7d0f2b
+permissions['stream_out'] = 'pull'
7d0f2b
 def stream(repo, proto):
7d0f2b
     '''If the server supports streaming clone, it advertises the "stream"
7d0f2b
     capability with a value representing the version and flags of the repo
7d0f2b
@@ -589,6 +628,7 @@
7d0f2b
 
7d0f2b
     return streamres(streamer(repo, entries, total_bytes))
7d0f2b
 
7d0f2b
+permissions['unbundle'] = 'push'
7d0f2b
 def unbundle(repo, proto, heads):
7d0f2b
     their_heads = decodelist(heads)
7d0f2b
 
7d0f2b
diff -r cceaf7af4c9e tests/get-with-headers.py
7d0f2b
--- a/tests/get-with-headers.py	Sat Jun 01 17:09:41 2013 -0500
7d0f2b
+++ b/tests/get-with-headers.py	Tue Jul 03 11:25:06 2018 +0200
7d0f2b
@@ -3,6 +3,7 @@
7d0f2b
 """This does HTTP GET requests given a host:port and path and returns
7d0f2b
 a subset of the headers plus the body of the result."""
7d0f2b
 
7d0f2b
+import argparse
7d0f2b
 import httplib, sys
7d0f2b
 
7d0f2b
 try:
7d0f2b
@@ -12,14 +13,22 @@
7d0f2b
 except ImportError:
7d0f2b
     pass
7d0f2b
 
7d0f2b
-twice = False
7d0f2b
-if '--twice' in sys.argv:
7d0f2b
-    sys.argv.remove('--twice')
7d0f2b
-    twice = True
7d0f2b
-headeronly = False
7d0f2b
-if '--headeronly' in sys.argv:
7d0f2b
-    sys.argv.remove('--headeronly')
7d0f2b
-    headeronly = True
7d0f2b
+parser = argparse.ArgumentParser()
7d0f2b
+parser.add_argument('--twice', action='store_true')
7d0f2b
+parser.add_argument('--headeronly', action='store_true')
7d0f2b
+parser.add_argument('--requestheader', nargs='*', default=[],
7d0f2b
+                    help='Send an additional HTTP request header. Argument '
7d0f2b
+                         'value is <header>=<value>')
7d0f2b
+parser.add_argument('--bodyfile',
7d0f2b
+                    help='Write HTTP response body to a file')
7d0f2b
+parser.add_argument('host')
7d0f2b
+parser.add_argument('path')
7d0f2b
+parser.add_argument('show', nargs='*')
7d0f2b
+args = parser.parse_args()
7d0f2b
+
7d0f2b
+twice = args.twice
7d0f2b
+headeronly = args.headeronly
7d0f2b
+requestheaders = args.requestheader
7d0f2b
 
7d0f2b
 reasons = {'Not modified': 'Not Modified'} # python 2.4
7d0f2b
 
7d0f2b
@@ -31,6 +40,10 @@
7d0f2b
     if tag:
7d0f2b
         headers['If-None-Match'] = tag
7d0f2b
 
7d0f2b
+    for header in requestheaders:
7d0f2b
+        key, value = header.split('=', 1)
7d0f2b
+        headers[key] = value
7d0f2b
+
7d0f2b
     conn = httplib.HTTPConnection(host)
7d0f2b
     conn.request("GET", '/' + path, None, headers)
7d0f2b
     response = conn.getresponse()
7d0f2b
@@ -44,16 +57,22 @@
7d0f2b
     if not headeronly:
7d0f2b
         print
7d0f2b
         data = response.read()
7d0f2b
-        sys.stdout.write(data)
7d0f2b
+        if args.bodyfile:
7d0f2b
+            bodyfh = open(args.bodyfile, 'wb')
7d0f2b
+        else:
7d0f2b
+            bodyfh = sys.stdout
7d0f2b
+        bodyfh.write(data)
7d0f2b
 
7d0f2b
         if twice and response.getheader('ETag', None):
7d0f2b
             tag = response.getheader('ETag')
7d0f2b
 
7d0f2b
+        if args.bodyfile:
7d0f2b
+            bodyfh.close()
7d0f2b
     return response.status
7d0f2b
 
7d0f2b
-status = request(sys.argv[1], sys.argv[2], sys.argv[3:])
7d0f2b
+status = request(args.host, args.path, args.show)
7d0f2b
 if twice:
7d0f2b
-    status = request(sys.argv[1], sys.argv[2], sys.argv[3:])
7d0f2b
+    status = request(args.host, args.path, args.show)
7d0f2b
 
7d0f2b
 if 200 <= status <= 305:
7d0f2b
     sys.exit(0)
7d0f2b
diff -r cceaf7af4c9e tests/killdaemons.py
7d0f2b
--- a/tests/killdaemons.py	Sat Jun 01 17:09:41 2013 -0500
7d0f2b
+++ b/tests/killdaemons.py	Tue Jul 03 11:25:06 2018 +0200
7d0f2b
@@ -49,6 +49,10 @@
7d0f2b
         pass
7d0f2b
 
7d0f2b
 if __name__ == '__main__':
7d0f2b
-    path, = sys.argv[1:]
7d0f2b
+    if len(sys.argv) > 1:
7d0f2b
+        path, = sys.argv[1:]
7d0f2b
+    else:
7d0f2b
+        path = os.environ["DAEMON_PIDS"]
7d0f2b
+
7d0f2b
     killdaemons(path)
7d0f2b
 
7d0f2b
diff -r cceaf7af4c9e tests/run-tests.py
7d0f2b
--- a/tests/run-tests.py	Sat Jun 01 17:09:41 2013 -0500
7d0f2b
+++ b/tests/run-tests.py	Tue Jul 03 11:25:06 2018 +0200
7d0f2b
@@ -1321,6 +1321,7 @@
7d0f2b
     os.environ["HGPORT"] = str(options.port)
7d0f2b
     os.environ["HGPORT1"] = str(options.port + 1)
7d0f2b
     os.environ["HGPORT2"] = str(options.port + 2)
7d0f2b
+    os.environ["LOCALIP"] = '127.0.0.1'
7d0f2b
 
7d0f2b
     if options.with_hg:
7d0f2b
         INST = None
7d0f2b
diff -r cceaf7af4c9e tests/test-http-permissions.t
7d0f2b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
7d0f2b
+++ b/tests/test-http-permissions.t	Tue Jul 03 11:25:06 2018 +0200
7d0f2b
@@ -0,0 +1,1491 @@
7d0f2b
+#require killdaemons
7d0f2b
+
7d0f2b
+  $ cat > fakeremoteuser.py << EOF
7d0f2b
+  > import os
7d0f2b
+  > from mercurial.hgweb import hgweb_mod
7d0f2b
+  > from mercurial import wireproto
7d0f2b
+  > class testenvhgweb(hgweb_mod.hgweb):
7d0f2b
+  >     def __call__(self, env, respond):
7d0f2b
+  >         # Allow REMOTE_USER to define authenticated user.
7d0f2b
+  >         if r'REMOTE_USER' in os.environ:
7d0f2b
+  >             env[r'REMOTE_USER'] = os.environ[r'REMOTE_USER']
7d0f2b
+  >         # Allow REQUEST_METHOD to override HTTP method
7d0f2b
+  >         if r'REQUEST_METHOD' in os.environ:
7d0f2b
+  >             env[r'REQUEST_METHOD'] = os.environ[r'REQUEST_METHOD']
7d0f2b
+  >         return super(testenvhgweb, self).__call__(env, respond)
7d0f2b
+  > hgweb_mod.hgweb = testenvhgweb
7d0f2b
+  > 
7d0f2b
+  > @wireproto.wireprotocommand('customreadnoperm')
7d0f2b
+  > def customread(repo, proto):
7d0f2b
+  >     return b'read-only command no defined permissions\n'
7d0f2b
+  > @wireproto.wireprotocommand('customwritenoperm')
7d0f2b
+  > def customwritenoperm(repo, proto):
7d0f2b
+  >     return b'write command no defined permissions\n'
7d0f2b
+  > wireproto.permissions['customreadwithperm'] = 'pull'
7d0f2b
+  > @wireproto.wireprotocommand('customreadwithperm')
7d0f2b
+  > def customreadwithperm(repo, proto):
7d0f2b
+  >     return b'read-only command w/ defined permissions\n'
7d0f2b
+  > wireproto.permissions['customwritewithperm'] = 'push'
7d0f2b
+  > @wireproto.wireprotocommand('customwritewithperm')
7d0f2b
+  > def customwritewithperm(repo, proto):
7d0f2b
+  >     return b'write command w/ defined permissions\n'
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ cat >> $HGRCPATH << EOF
7d0f2b
+  > [extensions]
7d0f2b
+  > fakeremoteuser = $TESTTMP/fakeremoteuser.py
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ hg init test
7d0f2b
+  $ cd test
7d0f2b
+  $ echo a > a
7d0f2b
+  $ hg ci -Ama
7d0f2b
+  adding a
7d0f2b
+  $ cd ..
7d0f2b
+  $ hg clone test test2
7d0f2b
+  updating to branch default
7d0f2b
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7d0f2b
+  $ cd test2
7d0f2b
+  $ echo a >> a
7d0f2b
+  $ hg ci -mb
7d0f2b
+  $ hg book bm -r 0
7d0f2b
+  $ cd ../test
7d0f2b
+
7d0f2b
+web.deny_read=* prevents access to wire protocol for all users
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > deny_read = *
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=capabilities'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=stream_out'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_read=* with REMOTE_USER set still locks out clients
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=capabilities'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=stream_out'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_read=<user> denies access to unauthenticated user
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > deny_read = baduser1,baduser2
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_read=<user> denies access to users in deny list
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=baduser2 hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_read=<user> allows access to authenticated users not in list
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b	1
7d0f2b
+  publishing	True (no-eol)
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b	1
7d0f2b
+  publishing	True (no-eol)
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  read-only command w/ defined permissions
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  pulling from http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_read=* allows reads for unauthenticated users
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > allow_read = *
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b	1
7d0f2b
+  publishing	True (no-eol)
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b	1
7d0f2b
+  publishing	True (no-eol)
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  read-only command w/ defined permissions
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  pulling from http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_read=* allows read for authenticated user
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=authed_user hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b	1
7d0f2b
+  publishing	True (no-eol)
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b	1
7d0f2b
+  publishing	True (no-eol)
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  read-only command w/ defined permissions
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  pulling from http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_read=<user> does not allow unauthenticated users to read
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > allow_read = gooduser
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_read=<user> does not allow user not in list to read
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_read=<user> allows read from user in list
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b	1
7d0f2b
+  publishing	True (no-eol)
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b	1
7d0f2b
+  publishing	True (no-eol)
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  read-only command w/ defined permissions
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  pulling from http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_read takes precedence over web.allow_read
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > allow_read = baduser
7d0f2b
+  > deny_read = baduser
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allowpull=false denies read access to repo
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > allowpull = false
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=capabilities'
7d0f2b
+  401 pull not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  pull not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=listkeys' --requestheader 'x-hgarg-1=namespace=phases'
7d0f2b
+  401 pull not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  pull not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=listkeys+namespace%3Dphases'
7d0f2b
+  401 pull not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  pull not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadwithperm'
7d0f2b
+  401 pull not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  pull not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 pull http://localhost:$HGPORT/
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+Attempting a write command with HTTP GET fails
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ REQUEST_METHOD=GET hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+  $ hg bookmark -d bm
7d0f2b
+  abort: bookmark 'bm' does not exist
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+Attempting a write command with an unknown HTTP verb fails
7d0f2b
+
7d0f2b
+  $ REQUEST_METHOD=someverb hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+  $ hg bookmark -d bm
7d0f2b
+  abort: bookmark 'bm' does not exist
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  405 push requires POST request
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push requires POST request
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+Pushing on a plaintext channel is disabled by default
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  200 ssl required
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  ssl required
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  200 ssl required
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  ssl required
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  200 ssl required
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  ssl required
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  200 ssl required
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  ssl required
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  remote: ssl required
7d0f2b
+  updating bookmark bm failed!
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  remote: ssl required
7d0f2b
+  remote: ssl required
7d0f2b
+  updating cb9a9f314b8b to public failed!
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_push=* denies pushing to unauthenticated users
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > push_ssl = false
7d0f2b
+  > deny_push = *
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_push=* denies pushing to authenticated users
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_push=<user> denies pushing to user in list
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > push_ssl = false
7d0f2b
+  > deny_push = baduser
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_push=<user> denies pushing to user not in list because allow_push isn't set
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_push=* allows pushes from unauthenticated users
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > push_ssl = false
7d0f2b
+  > allow_push = *
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  1
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+     bm                        0:cb9a9f314b8b
7d0f2b
+  $ hg book -d bm
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  write command no defined permissions
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  write command w/ defined permissions
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg book -d bm
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  remote: adding changesets
7d0f2b
+  remote: adding manifests
7d0f2b
+  remote: adding file changes
7d0f2b
+  remote: added 1 changesets with 1 changes to 1 files
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_push=* allows pushes from authenticated users
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  1
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+     bm                        0:cb9a9f314b8b
7d0f2b
+  $ hg book -d bm
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  write command no defined permissions
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  write command w/ defined permissions
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ cd ..
7d0f2b
+  $ rm -rf test2
7d0f2b
+  $ hg clone test test2
7d0f2b
+  updating to branch default
7d0f2b
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7d0f2b
+  $ cd test2
7d0f2b
+  $ echo a >> a
7d0f2b
+  $ hg ci -mb
7d0f2b
+  $ hg book bm -r 0
7d0f2b
+  $ cd ../test
7d0f2b
+  $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg book -d bm
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  remote: adding changesets
7d0f2b
+  remote: adding manifests
7d0f2b
+  remote: adding file changes
7d0f2b
+  remote: added 1 changesets with 1 changes to 1 files
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_push=<user> denies push to user not in list
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > push_ssl = false
7d0f2b
+  > allow_push = gooduser
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=baduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ cd ..
7d0f2b
+  $ rm -rf test2
7d0f2b
+  $ hg clone test test2
7d0f2b
+  updating to branch default
7d0f2b
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7d0f2b
+  $ cd test2
7d0f2b
+  $ echo a >> a
7d0f2b
+  $ hg ci -mb
7d0f2b
+  $ hg book bm -r 0
7d0f2b
+  $ cd ../test
7d0f2b
+  $ REMOTE_USER=baduser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_push=<user> allows push from user in list
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=gooduser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  1
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+     bm                        0:cb9a9f314b8b
7d0f2b
+  $ hg book -d bm
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  1
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+     bm                        0:cb9a9f314b8b
7d0f2b
+  $ hg book -d bm
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  write command no defined permissions
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  200 Script output follows
7d0f2b
+  
7d0f2b
+  write command w/ defined permissions
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ cd ..
7d0f2b
+  $ rm -rf test2
7d0f2b
+  $ hg clone test test2
7d0f2b
+  updating to branch default
7d0f2b
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7d0f2b
+  $ cd test2
7d0f2b
+  $ echo a >> a
7d0f2b
+  $ hg ci -mb
7d0f2b
+  $ hg book bm -r 0
7d0f2b
+  $ cd ../test
7d0f2b
+  $ REMOTE_USER=gooduser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg book -d bm
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  remote: adding changesets
7d0f2b
+  remote: adding manifests
7d0f2b
+  remote: adding file changes
7d0f2b
+  remote: added 1 changesets with 1 changes to 1 files
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.deny_push takes precedence over web.allow_push
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > push_ssl = false
7d0f2b
+  > allow_push = someuser
7d0f2b
+  > deny_push = someuser
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ REMOTE_USER=someuser REQUEST_METHOD=POST hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritenoperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customwritewithperm'
7d0f2b
+  401 push not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  push not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+Reset server to remove REQUEST_METHOD hack to test hg client
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+  $ cd ..
7d0f2b
+  $ rm -rf test2
7d0f2b
+  $ hg clone test test2
7d0f2b
+  updating to branch default
7d0f2b
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
7d0f2b
+  $ cd test2
7d0f2b
+  $ echo a >> a
7d0f2b
+  $ hg ci -mb
7d0f2b
+  $ hg book bm -r 0
7d0f2b
+  $ cd ../test
7d0f2b
+  $ REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push -B bm http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  no changes found
7d0f2b
+  exporting bookmark bm
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ hg --cwd ../test2 push http://localhost:$HGPORT/
7d0f2b
+  pushing to http://localhost:$HGPORT/
7d0f2b
+  searching for changes
7d0f2b
+  abort: authorization failed
7d0f2b
+  [255]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/killdaemons.py"
7d0f2b
+
7d0f2b
+web.allow_push has no effect if web.deny_read is set
7d0f2b
+
7d0f2b
+  $ cat > .hg/hgrc <
7d0f2b
+  > [web]
7d0f2b
+  > push_ssl = false
7d0f2b
+  > allow_push = *
7d0f2b
+  > deny_read = *
7d0f2b
+  > EOF
7d0f2b
+
7d0f2b
+  $ REQUEST_METHOD=POST REMOTE_USER=someuser hg serve -p $HGPORT -d --pid-file hg.pid
7d0f2b
+  $ cat hg.pid > $DAEMON_PIDS
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=pushkey' --requestheader 'x-hgarg-1=namespace=bookmarks&key=bm&old=&new=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=batch' --requestheader 'x-hgarg-1=cmds=pushkey+namespace%3Dbookmarks%2Ckey%3Dbm%2Cold%3D%2Cnew%3Dcb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
+
7d0f2b
+  $ hg bookmarks
7d0f2b
+  no bookmarks set
7d0f2b
+
7d0f2b
+  $ "$TESTDIR/get-with-headers.py" $LOCALIP:$HGPORT '?cmd=customreadnoperm'
7d0f2b
+  401 read not authorized
7d0f2b
+  
7d0f2b
+  0
7d0f2b
+  read not authorized
7d0f2b
+  [1]
7d0f2b
diff -r cceaf7af4c9e tests/test-pull-http.t
7d0f2b
--- a/tests/test-pull-http.t	Sat Jun 01 17:09:41 2013 -0500
7d0f2b
+++ b/tests/test-pull-http.t	Tue Jul 03 11:25:06 2018 +0200
7d0f2b
@@ -37,7 +37,6 @@
7d0f2b
   $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
7d0f2b
   $ cat hg.pid >> $DAEMON_PIDS
7d0f2b
   $ hg clone http://localhost:$HGPORT/ test4
7d0f2b
-  requesting all changes
7d0f2b
   abort: authorization failed
7d0f2b
   [255]
7d0f2b
   $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
7d0f2b
@@ -57,7 +56,6 @@
7d0f2b
 expect error, pulling not allowed
7d0f2b
 
7d0f2b
   $ req
7d0f2b
-  pulling from http://localhost:$HGPORT/
7d0f2b
   abort: authorization failed
7d0f2b
   % serve errors
7d0f2b