mercurial/wireprotoserver.py
author Gregory Szorc <gregory.szorc@gmail.com>
Wed, 07 Feb 2018 20:17:47 -0800
changeset 36104 2ad145fbde54
parent 36103 bf676267f64f
child 36105 caca3ac2ac04
permissions -rw-r--r--
wireprotoserver: add context manager mechanism for redirecting stdio Today, proto.redirect() sets up redirecting stdio and proto.restore() undoes that. The API is a bit wonky because restore() is only implemented on the HTTP protocol. Furthermore, not all calls to redirect() are obviously paired with calls to restore(). For example, the call to restore() for "unbundle" requests is handled by the response handler for the HTTP protocol. This commit introduces a new method on the protocol handler interface to maybe capture stdio. It emits a file object or None depending on whether stdio capture is used by the transport. To prove it works, the "pushkey" wire protocol command has been updated to use the new API. I'm not convinced this is the best mechanism to capture stdio. I may need to come up with something better once the new wire protocol emerges into existence. But it is strictly better than before because it removes variance in the wire protocol handler interface. It therefore gets us closer to a unified interface between the SSH and HTTP transports. Differential Revision: https://phab.mercurial-scm.org/D2081
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
35912
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35911
diff changeset
     9
import abc
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    10
import cgi
36104
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    11
import contextlib
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
    12
import struct
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
    13
import sys
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    14
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
    15
from .i18n import _
35896
ef3a24a023ec wireprotoserver: rename hgweb.protocol to wireprotoserver (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35750
diff changeset
    16
from . import (
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
    17
    encoding,
34509
e21f274cccea hgweb: in protocol adapter, avoid control reaching end of non-void function
Augie Fackler <augie@google.com>
parents: 33842
diff changeset
    18
    error,
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
    19
    hook,
34742
5a9cad0dfddb hgweb: when unpacking args from request form, convert to bytes
Augie Fackler <augie@google.com>
parents: 34740
diff changeset
    20
    pycompat,
27046
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    21
    util,
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    22
    wireproto,
37fcfe52c68c hgweb: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 20903
diff changeset
    23
)
35896
ef3a24a023ec wireprotoserver: rename hgweb.protocol to wireprotoserver (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35750
diff changeset
    24
28861
86db5cb55d46 pycompat: switch to util.stringio for py3 compat
timeless <timeless@mozdev.org>
parents: 28530
diff changeset
    25
stringio = util.stringio
5963
5be210afe1b8 hgweb: explicitly check if requested command exists
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5915
diff changeset
    26
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28861
diff changeset
    27
urlerr = util.urlerr
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28861
diff changeset
    28
urlreq = util.urlreq
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28861
diff changeset
    29
35898
1b76a9e0a9de wireprotoserver: don't import symbol from hgweb.common
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35897
diff changeset
    30
HTTP_OK = 200
1b76a9e0a9de wireprotoserver: don't import symbol from hgweb.common
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35897
diff changeset
    31
5993
948a41e77902 hgweb: explicit response status
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 5963
diff changeset
    32
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
    33
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
    34
HGERRTYPE = 'application/hg-error'
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
    35
36015
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35940
diff changeset
    36
# Names of the SSH protocol implementations.
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35940
diff changeset
    37
SSHV1 = 'ssh-v1'
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35940
diff changeset
    38
# 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: 35940
diff changeset
    39
# to reflect BC breakages.
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35940
diff changeset
    40
SSHV2 = 'exp-ssh-v2-0001'
48a3a9283f09 sshpeer: initial definition and implementation of new SSH protocol
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35940
diff changeset
    41
36027
04231e893a12 wireprotoserver: rename abstractserverproto and improve docstring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36026
diff changeset
    42
class baseprotocolhandler(object):
04231e893a12 wireprotoserver: rename abstractserverproto and improve docstring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36026
diff changeset
    43
    """Abstract base class for wire protocol handlers.
35900
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    44
36027
04231e893a12 wireprotoserver: rename abstractserverproto and improve docstring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36026
diff changeset
    45
    A wire protocol handler serves as an interface between protocol command
04231e893a12 wireprotoserver: rename abstractserverproto and improve docstring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36026
diff changeset
    46
    handlers and the wire protocol transport layer. Protocol handlers provide
04231e893a12 wireprotoserver: rename abstractserverproto and improve docstring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36026
diff changeset
    47
    methods to read command arguments, redirect stdio for the duration of
04231e893a12 wireprotoserver: rename abstractserverproto and improve docstring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36026
diff changeset
    48
    the request, handle response types, etc.
35900
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    49
    """
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    50
35912
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35911
diff changeset
    51
    __metaclass__ = abc.ABCMeta
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35911
diff changeset
    52
35913
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
    53
    @abc.abstractproperty
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
    54
    def name(self):
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
    55
        """The name of the protocol implementation.
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
    56
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
    57
        Used for uniquely identifying the transport type.
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
    58
        """
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
    59
35912
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35911
diff changeset
    60
    @abc.abstractmethod
35900
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    61
    def getargs(self, args):
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    62
        """return the value for arguments in <args>
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    63
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    64
        returns a list of values (same order as <args>)"""
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    65
35912
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35911
diff changeset
    66
    @abc.abstractmethod
35900
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    67
    def getfile(self, fp):
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    68
        """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: 35899
diff changeset
    69
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    70
        The file is in the form::
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    71
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    72
            (<chunk-size>\n<chunk>)+0\n
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    73
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    74
        chunk size is the ascii version of the int.
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    75
        """
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    76
35912
68dc621fa06c wireprotoserver: make abstractserverproto a proper abstract base class
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35911
diff changeset
    77
    @abc.abstractmethod
36104
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    78
    def mayberedirectstdio(self):
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    79
        """Context manager to possibly redirect stdio.
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    80
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    81
        The context manager yields a file-object like object that receives
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    82
        stdout and stderr output when the context manager is active. Or it
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    83
        yields ``None`` if no I/O redirection occurs.
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    84
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    85
        The intent of this context manager is to capture stdio output
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    86
        so it may be sent in the response. Some transports support streaming
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    87
        stdio to the client in real time. For these transports, stdio output
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    88
        won't be captured.
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    89
        """
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    90
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
    91
    @abc.abstractmethod
35900
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    92
    def redirect(self):
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    93
        """may setup interception for stdout and stderr
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    94
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    95
        See also the `restore` method."""
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    96
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    97
    # If the `redirect` function does install interception, the `restore`
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
    98
    # 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: 35899
diff changeset
    99
    # MUST NOT be defined.
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
   100
    #
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
   101
    # left commented here on purpose
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
   102
    #
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
   103
    #def restore(self):
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
   104
    #    """reinstall previous stdout and stderr and return intercepted stdout
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
   105
    #    """
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
   106
    #    raise NotImplementedError()
d9e71cce3b2f wireprotoserver: move abstractserverproto class from wireproto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35899
diff changeset
   107
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   108
def decodevaluefromheaders(req, headerprefix):
34744
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
   109
    """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
   110
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
   111
    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
   112
    """
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   113
    chunks = []
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   114
    i = 1
34744
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
   115
    prefix = headerprefix.upper().replace(r'-', r'_')
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   116
    while True:
34744
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
   117
        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: 30567
diff changeset
   118
        if v is None:
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   119
            break
34744
0a2ef612ad50 hgweb: fix decodevaluefromheaders to always return a bytes value
Augie Fackler <augie@google.com>
parents: 34743
diff changeset
   120
        chunks.append(pycompat.bytesurl(v))
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   121
        i += 1
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   122
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   123
    return ''.join(chunks)
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   124
36027
04231e893a12 wireprotoserver: rename abstractserverproto and improve docstring
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36026
diff changeset
   125
class webproto(baseprotocolhandler):
14614
afccc64eea73 ui: use I/O descriptors internally
Idan Kamara <idankk86@gmail.com>
parents: 14494
diff changeset
   126
    def __init__(self, req, ui):
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   127
        self._req = req
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   128
        self._ui = ui
35913
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
   129
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
   130
    @property
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
   131
    def name(self):
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
   132
        return 'http'
30567
b3a9ef3d30e8 protocol: declare transport protocol name
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30475
diff changeset
   133
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   134
    def getargs(self, args):
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   135
        knownargs = self._args()
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   136
        data = {}
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   137
        keys = args.split()
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   138
        for k in keys:
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   139
            if k == '*':
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   140
                star = {}
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   141
                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
   142
                    if key != 'cmd' and key not in keys:
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   143
                        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
   144
                data['*'] = star
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   145
            else:
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   146
                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
   147
        return [data[k] for k in keys]
35903
49426bb4476c wireprotoserver: add some blank lines between methods
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
   148
14093
ce99d887585f httprepo: long arguments support (issue2126)
Steven Brown <StevenGBrown@gmail.com>
parents: 13721
diff changeset
   149
    def _args(self):
35940
72de5c504833 py3: factor out helpers to apply string conversion recursively
Yuya Nishihara <yuya@tcha.org>
parents: 35913
diff changeset
   150
        args = util.rapply(pycompat.bytesurl, self._req.form.copy())
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   151
        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
   152
        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
   153
            args.update(cgi.parse_qs(
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   154
                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
   155
            return args
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   156
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   157
        argvalue = decodevaluefromheaders(self._req, r'X-HgArg')
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30567
diff changeset
   158
        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
   159
        return args
35903
49426bb4476c wireprotoserver: add some blank lines between methods
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
   160
11621
e46a8b2331a6 protocol: shuffle server methods to group send methods
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 11618
diff changeset
   161
    def getfile(self, fp):
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   162
        length = int(self._req.env[r'CONTENT_LENGTH'])
33842
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33228
diff changeset
   163
        # 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
   164
        # minus the amount that was consumed by args.
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   165
        length -= int(self._req.env.get(r'HTTP_X_HGARGS_POST', 0))
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   166
        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
   167
            fp.write(s)
35903
49426bb4476c wireprotoserver: add some blank lines between methods
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
   168
36104
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   169
    @contextlib.contextmanager
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   170
    def mayberedirectstdio(self):
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   171
        oldout = self._ui.fout
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   172
        olderr = self._ui.ferr
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   173
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   174
        out = util.stringio()
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   175
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   176
        try:
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   177
            self._ui.fout = out
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   178
            self._ui.ferr = out
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   179
            yield out
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   180
        finally:
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   181
            self._ui.fout = oldout
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   182
            self._ui.ferr = olderr
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   183
11621
e46a8b2331a6 protocol: shuffle server methods to group send methods
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 11618
diff changeset
   184
    def redirect(self):
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   185
        self._oldio = self._ui.fout, self._ui.ferr
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   186
        self._ui.ferr = self._ui.fout = stringio()
35903
49426bb4476c wireprotoserver: add some blank lines between methods
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35900
diff changeset
   187
14614
afccc64eea73 ui: use I/O descriptors internally
Idan Kamara <idankk86@gmail.com>
parents: 14494
diff changeset
   188
    def restore(self):
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   189
        val = self._ui.fout.getvalue()
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   190
        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
   191
        return val
30206
d105195436c0 wireproto: compress data from a generator
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30016
diff changeset
   192
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   193
    def _client(self):
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   194
        return 'remote:%s:%s:%s' % (
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   195
            self._req.env.get('wsgi.url_scheme') or 'http',
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   196
            urlreq.quote(self._req.env.get('REMOTE_HOST', '')),
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   197
            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
   198
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   199
    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
   200
        """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
   201
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   202
        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
   203
        """
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   204
        # 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
   205
        # on the request parameters.
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   206
        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
   207
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   208
        if '0.2' in protocaps:
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   209
            # 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
   210
            if prefer_uncompressed:
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   211
                return HGTYPE2, util._noopengine(), {}
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   212
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   213
            # 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
   214
            compformats = ['zlib', 'none']
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   215
            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
   216
                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
   217
                    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
   218
                    break
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   219
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   220
            # Now find an agreed upon compression format.
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   221
            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
   222
                                                         util.SERVERROLE):
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   223
                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
   224
                    opts = {}
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   225
                    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
   226
                                              '%slevel' % engine.name())
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   227
                    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
   228
                        opts['level'] = level
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   229
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   230
                    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
   231
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   232
            # 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
   233
            # legacy protocol.
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   234
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   235
        # 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
   236
        # 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
   237
        # the server's network or CPU.
35906
d747cf39cf70 wireprotoserver: make attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35905
diff changeset
   238
        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
   239
        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
   240
11595
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   241
def iscmd(cmd):
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   242
    return cmd in wireproto.commands
368cd5325348 protocol: move hgweb protocol support back into protocol.py
Matt Mackall <mpm@selenic.com>
parents: 11594
diff changeset
   243
36023
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   244
def parsehttprequest(repo, req, query):
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   245
    """Parse the HTTP request for a wire protocol request.
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   246
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   247
    If the current request appears to be a wire protocol request, this
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   248
    function returns a dict with details about that request, including
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   249
    an ``abstractprotocolserver`` instance suitable for handling the
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   250
    request. Otherwise, ``None`` is returned.
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   251
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   252
    ``req`` is a ``wsgirequest`` instance.
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   253
    """
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   254
    # HTTP version 1 wire protocol requests are denoted by a "cmd" query
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   255
    # string parameter. If it isn't present, this isn't a wire protocol
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   256
    # request.
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   257
    if r'cmd' not in req.form:
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   258
        return None
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   259
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   260
    cmd = pycompat.sysbytes(req.form[r'cmd'][0])
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   261
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   262
    # The "cmd" request parameter is used by both the wire protocol and hgweb.
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   263
    # While not all wire protocol commands are available for all transports,
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   264
    # if we see a "cmd" value that resembles a known wire protocol command, we
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   265
    # route it to a protocol handler. This is better than routing possible
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   266
    # wire protocol requests to hgweb because it prevents hgweb from using
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   267
    # known wire protocol commands and it is less confusing for machine
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   268
    # clients.
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   269
    if cmd not in wireproto.commands:
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   270
        return None
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   271
35904
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35903
diff changeset
   272
    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
   273
36023
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   274
    return {
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   275
        'cmd': cmd,
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   276
        'proto': proto,
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   277
        'dispatch': lambda: _callhttp(repo, req, proto, cmd),
36025
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   278
        'handleerror': lambda ex: _handlehttperror(ex, req, cmd),
36023
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   279
    }
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   280
cdc93fe1da77 wireprotoserver: move protocol parsing and dispatch out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36021
diff changeset
   281
def _callhttp(repo, req, proto, cmd):
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   282
    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
   283
        # 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
   284
        # 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
   285
        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
   286
        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
   287
        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
   288
        yield name
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   289
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   290
        for chunk in gen:
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   291
            yield chunk
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   292
35904
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35903
diff changeset
   293
    rsp = wireproto.dispatch(repo, proto, cmd)
36021
5a56bf4180ad wireproto: function for testing if wire protocol command is available
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36015
diff changeset
   294
5a56bf4180ad wireproto: function for testing if wire protocol command is available
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36015
diff changeset
   295
    if not wireproto.commands.commandavailable(cmd, proto):
5a56bf4180ad wireproto: function for testing if wire protocol command is available
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36015
diff changeset
   296
        req.respond(HTTP_OK, HGERRTYPE,
5a56bf4180ad wireproto: function for testing if wire protocol command is available
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36015
diff changeset
   297
                    body=_('requested wire protocol command is not available '
5a56bf4180ad wireproto: function for testing if wire protocol command is available
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36015
diff changeset
   298
                           'over HTTP'))
5a56bf4180ad wireproto: function for testing if wire protocol command is available
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36015
diff changeset
   299
        return []
5a56bf4180ad wireproto: function for testing if wire protocol command is available
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36015
diff changeset
   300
34510
c23fa3103925 hgweb: in protocol adapter, look for bytes instances, not str
Augie Fackler <augie@google.com>
parents: 34509
diff changeset
   301
    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
   302
        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
   303
        return []
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   304
    elif isinstance(rsp, wireproto.streamres_legacy):
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   305
        gen = rsp.gen
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   306
        req.respond(HTTP_OK, HGTYPE)
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   307
        return gen
11626
2f8adc60e013 protocol: use generators instead of req.write() for hgweb stream responses
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 11625
diff changeset
   308
    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
   309
        gen = rsp.gen
30475
2add671bf55b wireproto: perform chunking and compression at protocol layer (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30376
diff changeset
   310
30764
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   311
        # 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
   312
        # is here because we only compress streamres at the moment.
35904
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35903
diff changeset
   313
        mediatype, engine, engineopts = proto.responsetype(
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35903
diff changeset
   314
            rsp.prefer_uncompressed)
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   315
        gen = engine.compressstream(gen, engineopts)
30475
2add671bf55b wireproto: perform chunking and compression at protocol layer (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30376
diff changeset
   316
35750
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   317
        if mediatype == HGTYPE2:
a39a9df7ecca wireproto: split streamres into legacy and modern case
Joerg Sonnenberger <joerg@bec.de>
parents: 35705
diff changeset
   318
            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
   319
e75463e3179f protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   320
        req.respond(HTTP_OK, mediatype)
30475
2add671bf55b wireproto: perform chunking and compression at protocol layer (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30376
diff changeset
   321
        return gen
11626
2f8adc60e013 protocol: use generators instead of req.write() for hgweb stream responses
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 11625
diff changeset
   322
    elif isinstance(rsp, wireproto.pushres):
35904
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35903
diff changeset
   323
        val = proto.restore()
18346
6c2563b2c1c6 hgweb: use Content-Length for pushres
Mads Kiilerich <mads@kiilerich.com>
parents: 15017
diff changeset
   324
        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
   325
        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
   326
        return []
12703
40bb5853fc4b wireproto: introduce pusherr() to deal with "unsynced changes" error
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11626
diff changeset
   327
    elif isinstance(rsp, wireproto.pusherr):
36026
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   328
        # This is the httplib workaround documented in _handlehttperror().
12704
ca6e2adc3e4d wireproto/http: drain the incoming bundle in case of errors
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 12703
diff changeset
   329
        req.drain()
36026
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   330
35904
bd38ccf4ecf6 wireprotoserver: rename p to proto
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35903
diff changeset
   331
        proto.restore()
12703
40bb5853fc4b wireproto: introduce pusherr() to deal with "unsynced changes" error
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 11626
diff changeset
   332
        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
   333
        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
   334
        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
   335
    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
   336
        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
   337
        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
   338
        return []
34509
e21f274cccea hgweb: in protocol adapter, avoid control reaching end of non-void function
Augie Fackler <augie@google.com>
parents: 33842
diff changeset
   339
    raise error.ProgrammingError('hgweb.protocol internal failure', rsp)
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   340
36025
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   341
def _handlehttperror(e, req, cmd):
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   342
    """Called when an ErrorResponse is raised during HTTP request processing."""
36026
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   343
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   344
    # Clients using Python's httplib are stateful: the HTTP client
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   345
    # won't process an HTTP response until all request data is
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   346
    # sent to the server. The intent of this code is to ensure
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   347
    # we always read HTTP request data from the client, thus
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   348
    # ensuring httplib transitions to a state that allows it to read
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   349
    # the HTTP response. In other words, it helps prevent deadlocks
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   350
    # on clients using httplib.
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   351
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   352
    if (req.env[r'REQUEST_METHOD'] == r'POST' and
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   353
        # But not if Expect: 100-continue is being used.
36025
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   354
        (req.env.get('HTTP_EXPECT',
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   355
                     '').lower() != '100-continue') or
36026
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   356
        # Or the non-httplib HTTP library is being advertised by
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   357
        # the client.
36025
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   358
        req.env.get('X-HgHttp2', '')):
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   359
        req.drain()
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   360
    else:
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   361
        req.headers.append((r'Connection', r'Close'))
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   362
36026
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   363
    # TODO This response body assumes the failed command was
6010fe1da619 wireprotoserver: document and improve the httplib workaround
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36025
diff changeset
   364
    # "unbundle." That assumption is not always valid.
36025
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   365
    req.respond(e, HGTYPE, body='0\n%s\n' % e)
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   366
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   367
    return ''
98a00aa0288d wireprotoserver: move error response handling out of hgweb
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36023
diff changeset
   368
36102
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   369
def _sshv1respondbytes(fout, value):
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   370
    """Send a bytes response for protocol version 1."""
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   371
    fout.write('%d\n' % len(value))
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   372
    fout.write(value)
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   373
    fout.flush()
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   374
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   375
def _sshv1respondstream(fout, source):
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   376
    write = fout.write
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   377
    for chunk in source.gen:
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   378
        write(chunk)
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   379
    fout.flush()
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   380
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   381
def _sshv1respondooberror(fout, ferr, rsp):
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   382
    ferr.write(b'%s\n-\n' % rsp)
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   383
    ferr.flush()
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   384
    fout.write(b'\n')
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   385
    fout.flush()
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   386
36103
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   387
class sshv1protocolhandler(baseprotocolhandler):
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   388
    """Handler for requests services via version 1 of SSH protocol."""
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   389
    def __init__(self, ui, fin, fout):
35910
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35909
diff changeset
   390
        self._ui = ui
36103
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   391
        self._fin = fin
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   392
        self._fout = fout
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   393
35913
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
   394
    @property
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
   395
    def name(self):
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
   396
        return 'ssh'
29759c46aa1a wireprotoserver: make name part of protocol interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35912
diff changeset
   397
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   398
    def getargs(self, args):
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   399
        data = {}
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   400
        keys = args.split()
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   401
        for n in xrange(len(keys)):
35910
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35909
diff changeset
   402
            argline = self._fin.readline()[:-1]
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   403
            arg, l = argline.split()
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   404
            if arg not in keys:
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   405
                raise error.Abort(_("unexpected parameter %r") % arg)
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   406
            if arg == '*':
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   407
                star = {}
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   408
                for k in xrange(int(l)):
35910
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35909
diff changeset
   409
                    argline = self._fin.readline()[:-1]
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   410
                    arg, l = argline.split()
35910
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35909
diff changeset
   411
                    val = self._fin.read(int(l))
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   412
                    star[arg] = val
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   413
                data['*'] = star
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   414
            else:
35910
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35909
diff changeset
   415
                val = self._fin.read(int(l))
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   416
                data[arg] = val
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   417
        return [data[k] for k in keys]
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   418
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   419
    def getfile(self, fpout):
36102
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   420
        _sshv1respondbytes(self._fout, b'')
35910
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35909
diff changeset
   421
        count = int(self._fin.readline())
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   422
        while count:
35910
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35909
diff changeset
   423
            fpout.write(self._fin.read(count))
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35909
diff changeset
   424
            count = int(self._fin.readline())
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   425
36104
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   426
    @contextlib.contextmanager
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   427
    def mayberedirectstdio(self):
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   428
        yield None
2ad145fbde54 wireprotoserver: add context manager mechanism for redirecting stdio
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36103
diff changeset
   429
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   430
    def redirect(self):
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   431
        pass
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   432
36103
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   433
    def _client(self):
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   434
        client = encoding.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   435
        return 'remote:ssh:' + client
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   436
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   437
class sshserver(object):
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   438
    def __init__(self, ui, repo):
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   439
        self._ui = ui
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   440
        self._repo = repo
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   441
        self._fin = ui.fin
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   442
        self._fout = ui.fout
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   443
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   444
        hook.redirect(True)
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   445
        ui.fout = repo.ui.fout = ui.ferr
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   446
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   447
        # Prevent insertion/deletion of CRs
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   448
        util.setbinary(self._fin)
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   449
        util.setbinary(self._fout)
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   450
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   451
        self._proto = sshv1protocolhandler(self._ui, self._fin, self._fout)
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   452
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   453
    def serve_forever(self):
35908
5a9ff8c20123 wireprotoserver: remove lock references
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35907
diff changeset
   454
        while self.serve_one():
5a9ff8c20123 wireprotoserver: remove lock references
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35907
diff changeset
   455
            pass
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   456
        sys.exit(0)
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   457
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   458
    def serve_one(self):
35910
f1efc0caeab7 wireprotoserver: make some instance attributes private
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35909
diff changeset
   459
        cmd = self._fin.readline()[:-1]
36103
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   460
        if cmd and wireproto.commands.commandavailable(cmd, self._proto):
bf676267f64f wireprotoserver: split ssh protocol handler and server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36102
diff changeset
   461
            rsp = wireproto.dispatch(self._repo, self._proto, cmd)
36102
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   462
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   463
            if isinstance(rsp, bytes):
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   464
                _sshv1respondbytes(self._fout, rsp)
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   465
            elif isinstance(rsp, wireproto.streamres):
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   466
                _sshv1respondstream(self._fout, rsp)
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   467
            elif isinstance(rsp, wireproto.streamres_legacy):
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   468
                _sshv1respondstream(self._fout, rsp)
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   469
            elif isinstance(rsp, wireproto.pushres):
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   470
                _sshv1respondbytes(self._fout, b'')
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   471
                _sshv1respondbytes(self._fout, bytes(rsp.res))
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   472
            elif isinstance(rsp, wireproto.pusherr):
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   473
                _sshv1respondbytes(self._fout, rsp.res)
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   474
            elif isinstance(rsp, wireproto.ooberror):
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   475
                _sshv1respondooberror(self._fout, self._ui.ferr, rsp.message)
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   476
            else:
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   477
                raise error.ProgrammingError('unhandled response type from '
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   478
                                             'wire protocol command: %s' % rsp)
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   479
        elif cmd:
36102
5767664d39a5 wireprotoserver: extract SSH response handling functions
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36027
diff changeset
   480
            _sshv1respondbytes(self._fout, b'')
35899
1bf5263fe5cc wireprotoserver: move sshserver into module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35898
diff changeset
   481
        return cmd != ''