mercurial/wireprotoserver.py
author Gregory Szorc <gregory.szorc@gmail.com>
Tue, 06 Feb 2018 11:08:36 -0800
changeset 35976 48a3a9283f09
parent 35900 72de5c504833
child 35982 5a56bf4180ad
permissions -rw-r--r--
sshpeer: initial definition and implementation of new SSH protocol The existing SSH protocol has several design flaws. Future commits will elaborate on these flaws as new features are introduced to combat these flaws. For now, hopefully you can take me for my word that a ground up rewrite of the SSH protocol is needed. This commit lays the foundation for a new SSH protocol by defining a mechanism to upgrade the SSH transport channel away from the default (version 1) protocol to something modern (which we'll call "version 2" for now). This upgrade process is detailed in the internals documentation for the wire protocol. The gist of it is the client sends a request line preceding the "hello" command/line which basically says "I'm requesting an upgrade: here's what I support." If the server recognizes that line, it processes the upgrade request and the transport channel is switched to use the new version of the protocol. If not, it sends an empty response, which is how all Mercurial SSH servers from the beginning of time reacted to unknown commands. The upgrade request is effectively ignored and the client continues to use the existing version of the protocol as if nothing happened. The new version of the SSH protocol is completely identical to version 1 aside from the upgrade dance and the bytes that follow. The immediate bytes that follow the protocol switch are defined to be a length framed "capabilities: " line containing the remote's advertised capabilities. In reality, this looks very similar to what the "hello" response would look like. But it will evolve quickly. The methodology by which the protocol will evolve is important. I'm not going to introduce the new protocol all at once. That would likely lead to endless bike shedding and forward progress would stall. Instead, I intend to tricle out new features and diversions from the existing protocol in small, incremental changes. To support the gradual evolution of the protocol, the on-the-wire advertised protocol name contains an "exp" to denote "experimental" and a 4 digit field to capture the sub-version of the protocol. Whenever we make a BC change to the wire protocol, we can increment this version and lock out all older clients because it will appear as a completely different protocol version. This means we can incur as many breaking changes as we want. We don't have to commit to supporting any one feature or idea for a long period of time. We can even evolve the handshake mechanism, because that is defined as being an implementation detail of the negotiated protocol version! Hopefully this lowers the barrier to accepting changes to the protocol and for experimenting with "radical" ideas during its development. In core, sshpeer received most of the attention. We haven't even implemented the server bits for the new protocol in core yet. Instead, we add very primitive support to our test server, mainly just to exercise the added code paths in sshpeer. Differential Revision: https://phab.mercurial-scm.org/D2061 # no-check-commit because of required foo_bar naming
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
# 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
     2
# 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
     3
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8109
diff changeset
     4
# 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
     5
# 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
     6
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
     7
from __future__ import absolute_import
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
     8
35872
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35871
diff changeset
     9
import abc
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    10
import cgi
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
    11
import struct
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
    12
import sys
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    13
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
    14
from .i18n import _
35856
ef3a24a023ec wireprotoserver: rename hgweb.protocol to wireprotoserver (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35750
diff changeset
    15
from . import (
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
    16
    encoding,
34509
e21f274cccea hgweb: in protocol adapter, avoid control reaching end of non-void function
Augie Fackler <augie@google.com>
parents: 33821
diff changeset
    17
    error,
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
    18
    hook,
34742
5a9cad0dfddb hgweb: when unpacking args from request form, convert to bytes
Augie Fackler <augie@google.com>
parents: 34740
diff changeset
    19
    pycompat,
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    20
    util,
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    21
    wireproto,
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    22
)
35856
ef3a24a023ec wireprotoserver: rename hgweb.protocol to wireprotoserver (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35750
diff changeset
    23
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28530
diff changeset
    24
stringio = util.stringio
5963
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    25
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28861
diff changeset
    26
urlerr = util.urlerr
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28861
diff changeset
    27
urlreq = util.urlreq
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28861
diff changeset
    28
35858
1b76a9e0a9de wireprotoserver: don't import symbol from hgweb.common
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35857
diff changeset
    29
HTTP_OK = 200
1b76a9e0a9de wireprotoserver: don't import symbol from hgweb.common
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35857
diff changeset
    30
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    31
HGTYPE = 'application/mercurial-0.1'
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
    32
HGTYPE2 = 'application/mercurial-0.2'
15017
f4522df38c65 wireproto: add out-of-band error class to allow remote repo to report errors
Andrew Pritchard <andrewp@fogcreek.com>
parents: 14614
diff changeset
    33
HGERRTYPE = 'application/hg-error'
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
    34
35976
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
    35
# Names of the SSH protocol implementations.
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
    36
SSHV1 = 'ssh-v1'
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
    37
# This is advertised over the wire. Incremental the counter at the end
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
    38
# to reflect BC breakages.
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
    39
SSHV2 = 'exp-ssh-v2-0001'
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
    40
35860
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    41
class abstractserverproto(object):
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    42
    """abstract class that summarizes the protocol API
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    43
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    44
    Used as reference and documentation.
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    45
    """
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    46
35872
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35871
diff changeset
    47
    __metaclass__ = abc.ABCMeta
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35871
diff changeset
    48
35873
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
    49
    @abc.abstractproperty
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
    50
    def name(self):
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
    51
        """The name of the protocol implementation.
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
    52
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
    53
        Used for uniquely identifying the transport type.
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
    54
        """
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
    55
35872
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35871
diff changeset
    56
    @abc.abstractmethod
35860
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    57
    def getargs(self, args):
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    58
        """return the value for arguments in <args>
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    59
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    60
        returns a list of values (same order as <args>)"""
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    61
35872
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35871
diff changeset
    62
    @abc.abstractmethod
35860
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    63
    def getfile(self, fp):
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    64
        """write the whole content of a file into a file like object
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    65
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    66
        The file is in the form::
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    67
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    68
            (<chunk-size>\n<chunk>)+0\n
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    69
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    70
        chunk size is the ascii version of the int.
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    71
        """
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    72
35872
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35871
diff changeset
    73
    @abc.abstractmethod
35860
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    74
    def redirect(self):
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    75
        """may setup interception for stdout and stderr
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    76
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    77
        See also the `restore` method."""
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    78
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    79
    # If the `redirect` function does install interception, the `restore`
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    80
    # function MUST be defined. If interception is not used, this function
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    81
    # MUST NOT be defined.
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    82
    #
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    83
    # left commented here on purpose
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    84
    #
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    85
    #def restore(self):
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    86
    #    """reinstall previous stdout and stderr and return intercepted stdout
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    87
    #    """
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    88
    #    raise NotImplementedError()
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
    89
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
    90
def decodevaluefromheaders(req, headerprefix):
34744
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
    91
    """Decode a long value from multiple HTTP request headers.
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
    92
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
    93
    Returns the value as a bytes, not a str.
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
    94
    """
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
    95
    chunks = []
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
    96
    i = 1
34744
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
    97
    prefix = headerprefix.upper().replace(r'-', r'_')
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
    98
    while True:
34744
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
    99
        v = req.env.get(r'HTTP_%s_%d' % (prefix, i))
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
   100
        if v is None:
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
   101
            break
34744
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
   102
        chunks.append(pycompat.bytesurl(v))
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
   103
        i += 1
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
   104
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
   105
    return ''.join(chunks)
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
   106
35860
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
   107
class webproto(abstractserverproto):
14614
afccc64eea73 ui: use I/O descriptors internally
Idan Kamara <idankk86@gmail.com>
parents: 14494
diff changeset
   108
    def __init__(self, req, ui):
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   109
        self._req = req
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   110
        self._ui = ui
35873
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
   111
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
   112
    @property
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
   113
    def name(self):
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
   114
        return 'http'
30562
b3a9ef3d30e8 protocol: declare transport protocol name
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30466
diff changeset
   115
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   116
    def getargs(self, args):
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   117
        knownargs = self._args()
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   118
        data = {}
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   119
        keys = args.split()
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   120
        for k in keys:
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   121
            if k == '*':
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   122
                star = {}
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   123
                for key in knownargs.keys():
13721
3458c15ab2f0 wireproto: fix handling of '*' args for HTTP and SSH
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 12704
diff changeset
   124
                    if key != 'cmd' and key not in keys:
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   125
                        star[key] = knownargs[key][0]
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   126
                data['*'] = star
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   127
            else:
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   128
                data[k] = knownargs[k][0]
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   129
        return [data[k] for k in keys]
35863
49426bb4476c wireprotoserver: add some blank lines between methods
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35860
diff changeset
   130
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   131
    def _args(self):
35900
72de5c504833 py3: factor out helpers to apply string conversion recursively
Yuya Nishihara <yuya@tcha.org>
parents: 35873
diff changeset
   132
        args = util.rapply(pycompat.bytesurl, self._req.form.copy())
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   133
        postlen = int(self._req.env.get(r'HTTP_X_HGARGS_POST', 0))
28530
fd2acc5046f6 http: support sending hgargs via POST body instead of in GET or headers
Augie Fackler <augie@google.com>
parents: 27046
diff changeset
   134
        if postlen:
fd2acc5046f6 http: support sending hgargs via POST body instead of in GET or headers
Augie Fackler <augie@google.com>
parents: 27046
diff changeset
   135
            args.update(cgi.parse_qs(
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   136
                self._req.read(postlen), keep_blank_values=True))
28530
fd2acc5046f6 http: support sending hgargs via POST body instead of in GET or headers
Augie Fackler <augie@google.com>
parents: 27046
diff changeset
   137
            return args
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
   138
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   139
        argvalue = decodevaluefromheaders(self._req, r'X-HgArg')
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30562
diff changeset
   140
        args.update(cgi.parse_qs(argvalue, keep_blank_values=True))
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   141
        return args
35863
49426bb4476c wireprotoserver: add some blank lines between methods
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35860
diff changeset
   142
11621
e46a8b2331a6 protocol: shuffle server methods to group send methods
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 11618
diff changeset
   143
    def getfile(self, fp):
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   144
        length = int(self._req.env[r'CONTENT_LENGTH'])
33821
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33228
diff changeset
   145
        # If httppostargs is used, we need to read Content-Length
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33228
diff changeset
   146
        # minus the amount that was consumed by args.
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   147
        length -= int(self._req.env.get(r'HTTP_X_HGARGS_POST', 0))
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   148
        for s in util.filechunkiter(self._req, limit=length):
11621
e46a8b2331a6 protocol: shuffle server methods to group send methods
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 11618
diff changeset
   149
            fp.write(s)
35863
49426bb4476c wireprotoserver: add some blank lines between methods
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35860
diff changeset
   150
11621
e46a8b2331a6 protocol: shuffle server methods to group send methods
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 11618
diff changeset
   151
    def redirect(self):
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   152
        self._oldio = self._ui.fout, self._ui.ferr
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   153
        self._ui.ferr = self._ui.fout = stringio()
35863
49426bb4476c wireprotoserver: add some blank lines between methods
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35860
diff changeset
   154
14614
afccc64eea73 ui: use I/O descriptors internally
Idan Kamara <idankk86@gmail.com>
parents: 14494
diff changeset
   155
    def restore(self):
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   156
        val = self._ui.fout.getvalue()
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   157
        self._ui.ferr, self._ui.fout = self._oldio
14614
afccc64eea73 ui: use I/O descriptors internally
Idan Kamara <idankk86@gmail.com>
parents: 14494
diff changeset
   158
        return val
30206
d105195436c0 wireproto: compress data from a generator
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30014
diff changeset
   159
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   160
    def _client(self):
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   161
        return 'remote:%s:%s:%s' % (
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   162
            self._req.env.get('wsgi.url_scheme') or 'http',
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   163
            urlreq.quote(self._req.env.get('REMOTE_HOST', '')),
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   164
            urlreq.quote(self._req.env.get('REMOTE_USER', '')))
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   165
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   166
    def responsetype(self, prefer_uncompressed):
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   167
        """Determine the appropriate response type and compression settings.
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   168
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   169
        Returns a tuple of (mediatype, compengine, engineopts).
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   170
        """
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   171
        # Determine the response media type and compression engine based
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   172
        # on the request parameters.
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   173
        protocaps = decodevaluefromheaders(self._req, r'X-HgProto').split(' ')
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   174
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   175
        if '0.2' in protocaps:
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   176
            # All clients are expected to support uncompressed data.
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   177
            if prefer_uncompressed:
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   178
                return HGTYPE2, util._noopengine(), {}
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   179
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   180
            # Default as defined by wire protocol spec.
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   181
            compformats = ['zlib', 'none']
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   182
            for cap in protocaps:
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   183
                if cap.startswith('comp='):
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   184
                    compformats = cap[5:].split(',')
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   185
                    break
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   186
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   187
            # Now find an agreed upon compression format.
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   188
            for engine in wireproto.supportedcompengines(self._ui, self,
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   189
                                                         util.SERVERROLE):
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   190
                if engine.wireprotosupport().name in compformats:
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   191
                    opts = {}
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   192
                    level = self._ui.configint('server',
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   193
                                              '%slevel' % engine.name())
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   194
                    if level is not None:
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   195
                        opts['level'] = level
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   196
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   197
                    return HGTYPE2, engine, opts
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   198
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   199
            # No mutually supported compression format. Fall back to the
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   200
            # legacy protocol.
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   201
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   202
        # Don't allow untrusted settings because disabling compression or
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   203
        # setting a very high compression level could lead to flooding
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   204
        # the server's network or CPU.
35866
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35865
diff changeset
   205
        opts = {'level': self._ui.configint('server', 'zliblevel')}
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   206
        return HGTYPE, util.compengines['zlib'], opts
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   207
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   208
def iscmd(cmd):
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   209
    return cmd in wireproto.commands
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   210
35857
a42455b3dbf8 wireprotoserver: rename call to callhttp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35856
diff changeset
   211
def callhttp(repo, req, cmd):
35864
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35863
diff changeset
   212
    proto = webproto(req, repo.ui)
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   213
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   214
    def genversion2(gen, engine, engineopts):
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   215
        # application/mercurial-0.2 always sends a payload header
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   216
        # identifying the compression engine.
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   217
        name = engine.wireprotosupport().name
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   218
        assert 0 < len(name) < 256
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   219
        yield struct.pack('B', len(name))
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   220
        yield name
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   221
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   222
        for chunk in gen:
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   223
            yield chunk
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   224
35864
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35863
diff changeset
   225
    rsp = wireproto.dispatch(repo, proto, cmd)
34510
c23fa3103925 hgweb: in protocol adapter, look for bytes instances, not str
Augie Fackler <augie@google.com>
parents: 34509
diff changeset
   226
    if isinstance(rsp, bytes):
18352
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18346
diff changeset
   227
        req.respond(HTTP_OK, HGTYPE, body=rsp)
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18346
diff changeset
   228
        return []
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   229
    elif isinstance(rsp, wireproto.streamres_legacy):
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   230
        gen = rsp.gen
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   231
        req.respond(HTTP_OK, HGTYPE)
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   232
        return gen
11626
2f8adc60e013 protocol: use generators instead of req.write() for hgweb stream responses
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 11625
diff changeset
   233
    elif isinstance(rsp, wireproto.streamres):
35705
8cdb671dbd0b wireproto: drop support for reader interface from streamres (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 34744
diff changeset
   234
        gen = rsp.gen
30466
2add671bf55b wireproto: perform chunking and compression at protocol layer (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30366
diff changeset
   235
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   236
        # This code for compression should not be streamres specific. It
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   237
        # is here because we only compress streamres at the moment.
35864
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35863
diff changeset
   238
        mediatype, engine, engineopts = proto.responsetype(
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35863
diff changeset
   239
            rsp.prefer_uncompressed)
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   240
        gen = engine.compressstream(gen, engineopts)
30466
2add671bf55b wireproto: perform chunking and compression at protocol layer (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30366
diff changeset
   241
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   242
        if mediatype == HGTYPE2:
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   243
            gen = genversion2(gen, engine, engineopts)
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   244
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   245
        req.respond(HTTP_OK, mediatype)
30466
2add671bf55b wireproto: perform chunking and compression at protocol layer (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30366
diff changeset
   246
        return gen
11626
2f8adc60e013 protocol: use generators instead of req.write() for hgweb stream responses
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 11625
diff changeset
   247
    elif isinstance(rsp, wireproto.pushres):
35864
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35863
diff changeset
   248
        val = proto.restore()
18346
6c2563b2c1c6 hgweb: use Content-Length for pushres
Mads Kiilerich <mads@kiilerich.com>
parents: 15017
diff changeset
   249
        rsp = '%d\n%s' % (rsp.res, val)
18352
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18346
diff changeset
   250
        req.respond(HTTP_OK, HGTYPE, body=rsp)
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18346
diff changeset
   251
        return []
12703
40bb5853fc4b wireproto: introduce pusherr() to deal with "unsynced changes" error
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11626
diff changeset
   252
    elif isinstance(rsp, wireproto.pusherr):
12704
ca6e2adc3e4d wireproto/http: drain the incoming bundle in case of errors
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 12703
diff changeset
   253
        # drain the incoming bundle
ca6e2adc3e4d wireproto/http: drain the incoming bundle in case of errors
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 12703
diff changeset
   254
        req.drain()
35864
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35863
diff changeset
   255
        proto.restore()
12703
40bb5853fc4b wireproto: introduce pusherr() to deal with "unsynced changes" error
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11626
diff changeset
   256
        rsp = '0\n%s\n' % rsp.res
18352
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18346
diff changeset
   257
        req.respond(HTTP_OK, HGTYPE, body=rsp)
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18346
diff changeset
   258
        return []
15017
f4522df38c65 wireproto: add out-of-band error class to allow remote repo to report errors
Andrew Pritchard <andrewp@fogcreek.com>
parents: 14614
diff changeset
   259
    elif isinstance(rsp, wireproto.ooberror):
f4522df38c65 wireproto: add out-of-band error class to allow remote repo to report errors
Andrew Pritchard <andrewp@fogcreek.com>
parents: 14614
diff changeset
   260
        rsp = rsp.message
18352
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18346
diff changeset
   261
        req.respond(HTTP_OK, HGERRTYPE, body=rsp)
e33b9b92a200 hgweb: pass the actual response body to request.response, not just the length
Mads Kiilerich <mads@kiilerich.com>
parents: 18346
diff changeset
   262
        return []
34509
e21f274cccea hgweb: in protocol adapter, avoid control reaching end of non-void function
Augie Fackler <augie@google.com>
parents: 33821
diff changeset
   263
    raise error.ProgrammingError('hgweb.protocol internal failure', rsp)
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   264
35860
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35859
diff changeset
   265
class sshserver(abstractserverproto):
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   266
    def __init__(self, ui, repo):
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   267
        self._ui = ui
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   268
        self._repo = repo
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   269
        self._fin = ui.fin
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   270
        self._fout = ui.fout
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   271
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   272
        hook.redirect(True)
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   273
        ui.fout = repo.ui.fout = ui.ferr
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   274
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   275
        # Prevent insertion/deletion of CRs
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   276
        util.setbinary(self._fin)
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   277
        util.setbinary(self._fout)
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   278
35873
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
   279
    @property
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
   280
    def name(self):
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
   281
        return 'ssh'
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35872
diff changeset
   282
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   283
    def getargs(self, args):
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   284
        data = {}
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   285
        keys = args.split()
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   286
        for n in xrange(len(keys)):
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   287
            argline = self._fin.readline()[:-1]
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   288
            arg, l = argline.split()
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   289
            if arg not in keys:
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   290
                raise error.Abort(_("unexpected parameter %r") % arg)
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   291
            if arg == '*':
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   292
                star = {}
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   293
                for k in xrange(int(l)):
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   294
                    argline = self._fin.readline()[:-1]
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   295
                    arg, l = argline.split()
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   296
                    val = self._fin.read(int(l))
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   297
                    star[arg] = val
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   298
                data['*'] = star
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   299
            else:
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   300
                val = self._fin.read(int(l))
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   301
                data[arg] = val
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   302
        return [data[k] for k in keys]
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   303
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   304
    def getfile(self, fpout):
35871
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   305
        self._sendresponse('')
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   306
        count = int(self._fin.readline())
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   307
        while count:
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   308
            fpout.write(self._fin.read(count))
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   309
            count = int(self._fin.readline())
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   310
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   311
    def redirect(self):
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   312
        pass
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   313
35871
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   314
    def _sendresponse(self, v):
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   315
        self._fout.write("%d\n" % len(v))
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   316
        self._fout.write(v)
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   317
        self._fout.flush()
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   318
35871
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   319
    def _sendstream(self, source):
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   320
        write = self._fout.write
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   321
        for chunk in source.gen:
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   322
            write(chunk)
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   323
        self._fout.flush()
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   324
35871
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   325
    def _sendpushresponse(self, rsp):
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   326
        self._sendresponse('')
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   327
        self._sendresponse(str(rsp.res))
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   328
35871
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   329
    def _sendpusherror(self, rsp):
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   330
        self._sendresponse(rsp.res)
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   331
35871
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   332
    def _sendooberror(self, rsp):
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   333
        self._ui.ferr.write('%s\n-\n' % rsp.message)
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   334
        self._ui.ferr.flush()
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   335
        self._fout.write('\n')
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   336
        self._fout.flush()
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   337
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   338
    def serve_forever(self):
35868
5a9ff8c20123 wireprotoserver: remove lock references
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35867
diff changeset
   339
        while self.serve_one():
5a9ff8c20123 wireprotoserver: remove lock references
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35867
diff changeset
   340
            pass
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   341
        sys.exit(0)
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   342
35871
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   343
    _handlers = {
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   344
        str: _sendresponse,
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   345
        wireproto.streamres: _sendstream,
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   346
        wireproto.streamres_legacy: _sendstream,
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   347
        wireproto.pushres: _sendpushresponse,
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   348
        wireproto.pusherr: _sendpusherror,
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   349
        wireproto.ooberror: _sendooberror,
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   350
    }
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   351
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   352
    def serve_one(self):
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   353
        cmd = self._fin.readline()[:-1]
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   354
        if cmd and cmd in wireproto.commands:
35870
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35869
diff changeset
   355
            rsp = wireproto.dispatch(self._repo, self, cmd)
35871
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   356
            self._handlers[rsp.__class__](self, rsp)
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   357
        elif cmd:
35871
49ea1ba15ffd wireprotoserver: make response handling attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35870
diff changeset
   358
            self._sendresponse("")
35859
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   359
        return cmd != ''
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   360
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   361
    def _client(self):
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   362
        client = encoding.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35858
diff changeset
   363
        return 'remote:ssh:' + client