mercurial/hgweb/protocol.py
author Matt Mackall <mpm@selenic.com>
Fri, 25 Jun 2010 13:47:28 -0500
branchstable
changeset 11442 ee1ed6afac21
parent 11370 db3f6f0e4e7d
child 11582 26c7d4fc31bf
permissions -rw-r--r--
addchangegroup: pass in lock to release it before changegroup hook is called Currently, callers of addchangegroup first acquire the repository lock, usually to check that an unbundle request isn't racing. This means that changegroup hook actions that might write to a repo get stuck waiting for a lock. Here, we add a new optional lock parameter and update all the callers. Post-1.6 we may make it non-optional.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
     1
#
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
     2
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
     3
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
     4
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8109
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9713
diff changeset
     6
# GNU General Public License version 2 or any later version.
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
     7
9713
d193cc97c4e8 hgweb/sshserver: extract capabilities for easier modification
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9694
diff changeset
     8
import cStringIO, zlib, tempfile, errno, os, sys, urllib, copy
11370
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
     9
from mercurial import util, streamclone, pushkey
6211
f89fd07fc51d Expand import * to allow Pyflakes to find problems
Joel Rosdahl <joel@rosdahl.net>
parents: 6155
diff changeset
    10
from mercurial.node import bin, hex
6154
ef1c5a3b653d improve changegroup.readbundle(), use it in hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6152
diff changeset
    11
from mercurial import changegroup as changegroupmod
7281
f96c20e9b56a fix missing import, spotted by pychecker
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 7180
diff changeset
    12
from common import ErrorResponse, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    13
5963
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    14
# __all__ is populated with the allowed commands. Be sure to add to it if
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    15
# you're adding a new command, or the new command won't work.
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    16
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    17
__all__ = [
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    18
   'lookup', 'heads', 'branches', 'between', 'changegroup',
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    19
   'changegroupsubset', 'capabilities', 'unbundle', 'stream_out',
11370
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
    20
   'branchmap', 'pushkey', 'listkeys'
5963
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    21
]
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    22
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    23
HGTYPE = 'application/mercurial-0.1'
11370
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
    24
basecaps = 'lookup changegroupsubset branchmap pushkey'.split()
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    25
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    26
def lookup(repo, req):
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    27
    try:
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    28
        r = hex(repo.lookup(req.form['key'][0]))
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    29
        success = 1
9198
061eeb602354 coding style: use a space after comma
Martin Geisler <mg@lazybytes.net>
parents: 8846
diff changeset
    30
    except Exception, inst:
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    31
        r = str(inst)
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    32
        success = 0
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    33
    resp = "%s %s\n" % (success, r)
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    34
    req.respond(HTTP_OK, HGTYPE, length=len(resp))
6784
18c429ea3a0e hgweb: all protocol functions have become generators
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6782
diff changeset
    35
    yield resp
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    36
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    37
def heads(repo, req):
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    38
    resp = " ".join(map(hex, repo.heads())) + "\n"
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    39
    req.respond(HTTP_OK, HGTYPE, length=len(resp))
6784
18c429ea3a0e hgweb: all protocol functions have become generators
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6782
diff changeset
    40
    yield resp
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    41
8562
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    42
def branchmap(repo, req):
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    43
    branches = repo.branchmap()
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    44
    heads = []
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    45
    for branch, nodes in branches.iteritems():
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    46
        branchname = urllib.quote(branch)
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    47
        branchnodes = [hex(node) for node in nodes]
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    48
        heads.append('%s %s' % (branchname, ' '.join(branchnodes)))
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    49
    resp = '\n'.join(heads)
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    50
    req.respond(HTTP_OK, HGTYPE, length=len(resp))
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    51
    yield resp
e3495c399006 named branches: server branchmap wire protocol support (issue736)
Henrik Stuart <henrik.stuart@edlund.dk>
parents: 8225
diff changeset
    52
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    53
def branches(repo, req):
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    54
    nodes = []
5915
d0576d065993 Prefer i in d over d.has_key(i)
Christian Ebert <blacktrash@gmx.net>
parents: 5598
diff changeset
    55
    if 'nodes' in req.form:
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    56
        nodes = map(bin, req.form['nodes'][0].split(" "))
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    57
    resp = cStringIO.StringIO()
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    58
    for b in repo.branches(nodes):
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    59
        resp.write(" ".join(map(hex, b)) + "\n")
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    60
    resp = resp.getvalue()
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    61
    req.respond(HTTP_OK, HGTYPE, length=len(resp))
6784
18c429ea3a0e hgweb: all protocol functions have become generators
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6782
diff changeset
    62
    yield resp
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    63
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    64
def between(repo, req):
10530
ed87b6c60e0b hgweb: fix handling of arguments in the between command
Sune Foldager <cryo@cyanite.org>
parents: 10377
diff changeset
    65
    pairs = [map(bin, p.split("-"))
ed87b6c60e0b hgweb: fix handling of arguments in the between command
Sune Foldager <cryo@cyanite.org>
parents: 10377
diff changeset
    66
             for p in req.form['pairs'][0].split(" ")]
10531
e3eff76552f1 hgweb: use string join instead of slower cStringIO
Sune Foldager <cryo@cyanite.org>
parents: 10530
diff changeset
    67
    resp = ''.join(" ".join(map(hex, b)) + "\n" for b in repo.between(pairs))
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    68
    req.respond(HTTP_OK, HGTYPE, length=len(resp))
6784
18c429ea3a0e hgweb: all protocol functions have become generators
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6782
diff changeset
    69
    yield resp
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    70
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    71
def changegroup(repo, req):
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    72
    req.respond(HTTP_OK, HGTYPE)
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    73
    nodes = []
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    74
5915
d0576d065993 Prefer i in d over d.has_key(i)
Christian Ebert <blacktrash@gmx.net>
parents: 5598
diff changeset
    75
    if 'roots' in req.form:
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    76
        nodes = map(bin, req.form['roots'][0].split(" "))
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    77
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    78
    z = zlib.compressobj()
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    79
    f = repo.changegroup(nodes, 'serve')
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    80
    while 1:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    81
        chunk = f.read(4096)
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    82
        if not chunk:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    83
            break
6784
18c429ea3a0e hgweb: all protocol functions have become generators
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6782
diff changeset
    84
        yield z.compress(chunk)
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    85
6784
18c429ea3a0e hgweb: all protocol functions have become generators
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6782
diff changeset
    86
    yield z.flush()
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    87
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    88
def changegroupsubset(repo, req):
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    89
    req.respond(HTTP_OK, HGTYPE)
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    90
    bases = []
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    91
    heads = []
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    92
5915
d0576d065993 Prefer i in d over d.has_key(i)
Christian Ebert <blacktrash@gmx.net>
parents: 5598
diff changeset
    93
    if 'bases' in req.form:
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    94
        bases = [bin(x) for x in req.form['bases'][0].split(' ')]
5915
d0576d065993 Prefer i in d over d.has_key(i)
Christian Ebert <blacktrash@gmx.net>
parents: 5598
diff changeset
    95
    if 'heads' in req.form:
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    96
        heads = [bin(x) for x in req.form['heads'][0].split(' ')]
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    97
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
    98
    z = zlib.compressobj()
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
    99
    f = repo.changegroupsubset(bases, heads, 'serve')
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   100
    while 1:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   101
        chunk = f.read(4096)
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   102
        if not chunk:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   103
            break
6784
18c429ea3a0e hgweb: all protocol functions have become generators
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6782
diff changeset
   104
        yield z.compress(chunk)
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   105
6784
18c429ea3a0e hgweb: all protocol functions have become generators
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6782
diff changeset
   106
    yield z.flush()
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   107
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
   108
def capabilities(repo, req):
9713
d193cc97c4e8 hgweb/sshserver: extract capabilities for easier modification
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 9694
diff changeset
   109
    caps = copy.copy(basecaps)
10377
04e1e6743809 streamclone: allow uncompressed clones by default
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   110
    if streamclone.allowed(repo.ui):
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
   111
        caps.append('stream=%d' % repo.changelog.version)
6780
4c1d67e0fa8c hgweb: move capabilities calculation back into hgweb.protocol
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6779
diff changeset
   112
    if changegroupmod.bundlepriority:
4c1d67e0fa8c hgweb: move capabilities calculation back into hgweb.protocol
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6779
diff changeset
   113
        caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
4c1d67e0fa8c hgweb: move capabilities calculation back into hgweb.protocol
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6779
diff changeset
   114
    rsp = ' '.join(caps)
4c1d67e0fa8c hgweb: move capabilities calculation back into hgweb.protocol
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6779
diff changeset
   115
    req.respond(HTTP_OK, HGTYPE, length=len(rsp))
6784
18c429ea3a0e hgweb: all protocol functions have become generators
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6782
diff changeset
   116
    yield rsp
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   117
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
   118
def unbundle(repo, req):
6335
e29557d687c9 hgweb: only accept POST requests for unbundle
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6265
diff changeset
   119
6779
d3147b4e3e8a hgweb: centralize permission checks for protocol commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6630
diff changeset
   120
    proto = req.env.get('wsgi.url_scheme') or 'http'
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   121
    their_heads = req.form['heads'][0].split(' ')
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   122
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   123
    def check_heads():
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
   124
        heads = map(hex, repo.heads())
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   125
        return their_heads == [hex('force')] or their_heads == heads
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   126
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   127
    # fail early if possible
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   128
    if not check_heads():
7180
a42d27bc809d hgweb: be sure to drain request data even in early error conditions
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6926
diff changeset
   129
        req.drain()
6926
57b954d8d003 hgweb: raise ErrorResponses to communicate protocol errors
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6925
diff changeset
   130
        raise ErrorResponse(HTTP_OK, 'unsynced changes')
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   131
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   132
    # do not lock repo until all changegroup data is
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   133
    # streamed. save to temporary file.
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   134
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   135
    fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   136
    fp = os.fdopen(fd, 'wb+')
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   137
    try:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   138
        length = int(req.env['CONTENT_LENGTH'])
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   139
        for s in util.filechunkiter(req, limit=length):
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   140
            fp.write(s)
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   141
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   142
        try:
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
   143
            lock = repo.lock()
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   144
            try:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   145
                if not check_heads():
6926
57b954d8d003 hgweb: raise ErrorResponses to communicate protocol errors
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6925
diff changeset
   146
                    raise ErrorResponse(HTTP_OK, 'unsynced changes')
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   147
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   148
                fp.seek(0)
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   149
                header = fp.read(6)
6154
ef1c5a3b653d improve changegroup.readbundle(), use it in hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6152
diff changeset
   150
                if header.startswith('HG') and not header.startswith('HG10'):
ef1c5a3b653d improve changegroup.readbundle(), use it in hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6152
diff changeset
   151
                    raise ValueError('unknown bundle version')
ef1c5a3b653d improve changegroup.readbundle(), use it in hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6152
diff changeset
   152
                elif header not in changegroupmod.bundletypes:
ef1c5a3b653d improve changegroup.readbundle(), use it in hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6152
diff changeset
   153
                    raise ValueError('unknown bundle compression type')
ef1c5a3b653d improve changegroup.readbundle(), use it in hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6152
diff changeset
   154
                gen = changegroupmod.unbundle(header, fp)
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   155
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   156
                # send addchangegroup output to client
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   157
6265
be76e54570f0 Issue937: error messages from hooks not sent over HTTP.
Jesse Glick <jesse.glick@sun.com>
parents: 6212
diff changeset
   158
                oldio = sys.stdout, sys.stderr
be76e54570f0 Issue937: error messages from hooks not sent over HTTP.
Jesse Glick <jesse.glick@sun.com>
parents: 6212
diff changeset
   159
                sys.stderr = sys.stdout = cStringIO.StringIO()
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   160
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   161
                try:
8846
b30775386d40 acl: support for getting authenticated user from web server (issue298)
Henrik Stuart <hg@hstuart.dk>
parents: 8845
diff changeset
   162
                    url = 'remote:%s:%s:%s' % (
b30775386d40 acl: support for getting authenticated user from web server (issue298)
Henrik Stuart <hg@hstuart.dk>
parents: 8845
diff changeset
   163
                          proto,
b30775386d40 acl: support for getting authenticated user from web server (issue298)
Henrik Stuart <hg@hstuart.dk>
parents: 8845
diff changeset
   164
                          urllib.quote(req.env.get('REMOTE_HOST', '')),
b30775386d40 acl: support for getting authenticated user from web server (issue298)
Henrik Stuart <hg@hstuart.dk>
parents: 8845
diff changeset
   165
                          urllib.quote(req.env.get('REMOTE_USER', '')))
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   166
                    try:
11442
ee1ed6afac21 addchangegroup: pass in lock to release it before changegroup hook is called
Matt Mackall <mpm@selenic.com>
parents: 11370
diff changeset
   167
                        ret = repo.addchangegroup(gen, 'serve', url, lock=lock)
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   168
                    except util.Abort, inst:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   169
                        sys.stdout.write("abort: %s\n" % inst)
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   170
                        ret = 0
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   171
                finally:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   172
                    val = sys.stdout.getvalue()
6265
be76e54570f0 Issue937: error messages from hooks not sent over HTTP.
Jesse Glick <jesse.glick@sun.com>
parents: 6212
diff changeset
   173
                    sys.stdout, sys.stderr = oldio
6926
57b954d8d003 hgweb: raise ErrorResponses to communicate protocol errors
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6925
diff changeset
   174
                req.respond(HTTP_OK, HGTYPE)
6788
88a1bcc5c6a7 hgweb: use a single-element tuple to return from protocol.unbundle()
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6784
diff changeset
   175
                return '%d\n%s' % (ret, val),
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   176
            finally:
8109
496ae1ea4698 switch lock releasing in the core from gc to explicit
Ronny Pfannschmidt <Ronny.Pfannschmidt@gmx.de>
parents: 7281
diff changeset
   177
                lock.release()
6154
ef1c5a3b653d improve changegroup.readbundle(), use it in hgweb
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6152
diff changeset
   178
        except ValueError, inst:
6926
57b954d8d003 hgweb: raise ErrorResponses to communicate protocol errors
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6925
diff changeset
   179
            raise ErrorResponse(HTTP_OK, inst)
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   180
        except (OSError, IOError), inst:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   181
            error = getattr(inst, 'strerror', 'Unknown error')
10951
5dc09507b90e hgweb: fix attribute error in error response (issue2060)
Mark Determann <qwerty360@gmail.com>
parents: 10531
diff changeset
   182
            if not isinstance(error, str):
5dc09507b90e hgweb: fix attribute error in error response (issue2060)
Mark Determann <qwerty360@gmail.com>
parents: 10531
diff changeset
   183
                error = 'Error: %s' % str(error)
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   184
            if inst.errno == errno.ENOENT:
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
   185
                code = HTTP_NOT_FOUND
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   186
            else:
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
   187
                code = HTTP_SERVER_ERROR
9694
8269fe2d48f6 hgweb: send proper error messages to the client
Sune Foldager <cryo@cyanite.org>
parents: 9198
diff changeset
   188
            filename = getattr(inst, 'filename', '')
8269fe2d48f6 hgweb: send proper error messages to the client
Sune Foldager <cryo@cyanite.org>
parents: 9198
diff changeset
   189
            # Don't send our filesystem layout to the client
8269fe2d48f6 hgweb: send proper error messages to the client
Sune Foldager <cryo@cyanite.org>
parents: 9198
diff changeset
   190
            if filename and filename.startswith(repo.root):
8269fe2d48f6 hgweb: send proper error messages to the client
Sune Foldager <cryo@cyanite.org>
parents: 9198
diff changeset
   191
                filename = filename[len(repo.root)+1:]
8269fe2d48f6 hgweb: send proper error messages to the client
Sune Foldager <cryo@cyanite.org>
parents: 9198
diff changeset
   192
                text = '%s: %s' % (error, filename)
8269fe2d48f6 hgweb: send proper error messages to the client
Sune Foldager <cryo@cyanite.org>
parents: 9198
diff changeset
   193
            else:
8269fe2d48f6 hgweb: send proper error messages to the client
Sune Foldager <cryo@cyanite.org>
parents: 9198
diff changeset
   194
                text = error.replace(repo.root + os.path.sep, '')
8269fe2d48f6 hgweb: send proper error messages to the client
Sune Foldager <cryo@cyanite.org>
parents: 9198
diff changeset
   195
            raise ErrorResponse(code, text)
5598
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   196
    finally:
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   197
        fp.close()
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   198
        os.unlink(tempname)
d534ba1c4eb4 separate the wire protocol commands from the user interface commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
diff changeset
   199
6781
b4b7261164d5 hgweb: protocol functions take repo instead of web
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6780
diff changeset
   200
def stream_out(repo, req):
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
   201
    req.respond(HTTP_OK, HGTYPE)
6925
87abfefafe02 make streamclone.stream_out() a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6795
diff changeset
   202
    try:
10377
04e1e6743809 streamclone: allow uncompressed clones by default
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
   203
        for chunk in streamclone.stream_out(repo):
6925
87abfefafe02 make streamclone.stream_out() a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6795
diff changeset
   204
            yield chunk
87abfefafe02 make streamclone.stream_out() a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6795
diff changeset
   205
    except streamclone.StreamException, inst:
87abfefafe02 make streamclone.stream_out() a generator
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 6795
diff changeset
   206
        yield str(inst)
11370
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   207
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   208
def pushkey(repo, req):
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   209
    namespace = req.form['namespace'][0]
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   210
    key = req.form['key'][0]
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   211
    old = req.form['old'][0]
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   212
    new = req.form['new'][0]
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   213
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   214
    r = repo.pushkey(namespace, key, old, new)
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   215
    r = '%d\n' % int(r)
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   216
    req.respond(HTTP_OK, HGTYPE, length=len(r))
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   217
    yield r
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   218
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   219
def listkeys(repo, req):
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   220
    namespace = req.form['namespace'][0]
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   221
    d = repo.listkeys(namespace).items()
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   222
    t = '\n'.join(['%s\t%s' % (k.encode('string-escape'),
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   223
                               v.encode('string-escape')) for k, v in d])
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   224
    req.respond(HTTP_OK, HGTYPE, length=len(t))
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 10951
diff changeset
   225
    yield t