mercurial/httppeer.py
author Anton Shestakov <av6@dwimlabs.net>
Sat, 08 Sep 2018 21:58:51 +0800
changeset 39484 98995b689e03
parent 39483 1fc39367eafd
child 39549 089fc0db0954
permissions -rw-r--r--
httppeer: use util.readexactly() to abort on incomplete responses Plain resp.read(n) may not return exactly n bytes when we need, and to detect such cases before trying to interpret whatever has been read, we can use util.readexactly(), which raises an Abort when stream ends unexpectedly. In the first case here, readexactly() prevents a traceback with struct.error, in the second it avoids looking for invalid compression engines. In this test case, _wraphttpresponse doesn't catch the problem (presumably because it doesn't know transfer encoding), and the code continues reading the response until it gets to compression engine data. Maybe there should be checks before the execution gets there, but I'm not sure where (httplib?)
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
17192
1ac628cd7113 peer: introduce real peer classes
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 15246
diff changeset
     1
# httppeer.py - HTTP repository proxy classes for mercurial
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
     2
#
2859
345bac2bc4ec update copyrights.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2740
diff changeset
     3
# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
345bac2bc4ec update copyrights.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2740
diff changeset
     4
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
     5
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8206
diff changeset
     6
# 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: 9878
diff changeset
     7
# GNU General Public License version 2 or any later version.
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
     8
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     9
from __future__ import absolute_import
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    10
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    11
import errno
33821
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
    12
import io
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    13
import os
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    14
import socket
30763
a520aefb96f1 httppeer: advertise and support application/mercurial-0.2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
    15
import struct
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
    16
import weakref
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    17
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    18
from .i18n import _
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    19
from . import (
28666
ae53ecc47414 bundle: move writebundle() from changegroup.py to bundle2.py (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28530
diff changeset
    20
    bundle2,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    21
    error,
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    22
    httpconnection,
30924
48dea083f66d py3: convert the mode argument of os.fdopen to unicodes (1 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30763
diff changeset
    23
    pycompat,
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
    24
    repository,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    25
    statichttprepo,
36959
43815d87c6aa httppeer: alias url as urlmod
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36835
diff changeset
    26
    url as urlmod,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    27
    util,
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
    28
    wireprotoframing,
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
    29
    wireprototypes,
37614
a81d02ea65db wireproto: move version 1 peer functionality to standalone module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37611
diff changeset
    30
    wireprotov1peer,
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
    31
    wireprotov2peer,
37545
93397c4633f6 wireproto: extract HTTP version 2 code to own module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37544
diff changeset
    32
    wireprotov2server,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    33
)
37810
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
    34
from .utils import (
39445
cdb56f295b03 httppeer: use our CBOR decoder
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39437
diff changeset
    35
    cborutil,
37810
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
    36
    interfaceutil,
39436
3fe028b657bf httppeer: log commands for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38783
diff changeset
    37
    stringutil,
37810
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
    38
)
4678
a814a5b11fff Work around urllib2 digest auth bug with Python < 2.5
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4633
diff changeset
    39
29455
0c741fd6158a py3: conditionalize httplib import
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29241
diff changeset
    40
httplib = util.httplib
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
    41
urlerr = util.urlerr
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
    42
urlreq = util.urlreq
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
    43
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    44
def encodevalueinheaders(value, header, limit):
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    45
    """Encode a string value into multiple HTTP headers.
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    46
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    47
    ``value`` will be encoded into 1 or more HTTP headers with the names
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    48
    ``header-<N>`` where ``<N>`` is an integer starting at 1. Each header
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    49
    name + value will be at most ``limit`` bytes long.
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    50
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    51
    Returns an iterable of 2-tuples consisting of header names and
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    52
    values as native strings.
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    53
    """
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    54
    # HTTP Headers are ASCII. Python 3 requires them to be unicodes,
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    55
    # not bytes. This function always takes bytes in as arguments.
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    56
    fmt = pycompat.strurl(header) + r'-%s'
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    57
    # Note: it is *NOT* a bug that the last bit here is a bytestring
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    58
    # and not a unicode: we're just getting the encoded length anyway,
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    59
    # and using an r-string to make it portable between Python 2 and 3
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    60
    # doesn't work because then the \r is a literal backslash-r
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    61
    # instead of a carriage return.
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    62
    valuelen = limit - len(fmt % r'000') - len(': \r\n')
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    63
    result = []
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    64
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    65
    n = 0
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38502
diff changeset
    66
    for i in pycompat.xrange(0, len(value), valuelen):
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    67
        n += 1
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    68
        result.append((fmt % str(n), pycompat.strurl(value[i:i + valuelen])))
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    69
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    70
    return result
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    71
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    72
def _wraphttpresponse(resp):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    73
    """Wrap an HTTPResponse with common error handlers.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    74
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    75
    This ensures that any I/O from any consumer raises the appropriate
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    76
    error and messaging.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    77
    """
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    78
    origread = resp.read
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    79
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    80
    class readerproxy(resp.__class__):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    81
        def read(self, size=None):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    82
            try:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    83
                return origread(size)
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    84
            except httplib.IncompleteRead as e:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    85
                # e.expected is an integer if length known or None otherwise.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    86
                if e.expected:
39483
1fc39367eafd httppeer: calculate total expected bytes correctly
Anton Shestakov <av6@dwimlabs.net>
parents: 39445
diff changeset
    87
                    got = len(e.partial)
1fc39367eafd httppeer: calculate total expected bytes correctly
Anton Shestakov <av6@dwimlabs.net>
parents: 39445
diff changeset
    88
                    total = e.expected + got
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    89
                    msg = _('HTTP request error (incomplete response; '
39483
1fc39367eafd httppeer: calculate total expected bytes correctly
Anton Shestakov <av6@dwimlabs.net>
parents: 39445
diff changeset
    90
                            'expected %d bytes got %d)') % (total, got)
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    91
                else:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    92
                    msg = _('HTTP request error (incomplete response)')
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    93
32023
a29580905771 error: rename RichIOError to PeerTransportError
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32022
diff changeset
    94
                raise error.PeerTransportError(
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    95
                    msg,
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    96
                    hint=_('this may be an intermittent network failure; '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    97
                           'if the error persists, consider contacting the '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    98
                           'network or server operator'))
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    99
            except httplib.HTTPException as e:
32023
a29580905771 error: rename RichIOError to PeerTransportError
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32022
diff changeset
   100
                raise error.PeerTransportError(
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
   101
                    _('HTTP request error (%s)') % e,
32086
b59a292d0a53 httppeer: unify hint message for PeerTransportError
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 32023
diff changeset
   102
                    hint=_('this may be an intermittent network failure; '
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
   103
                           'if the error persists, consider contacting the '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
   104
                           'network or server operator'))
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
   105
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
   106
    resp.__class__ = readerproxy
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
   107
33821
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   108
class _multifile(object):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   109
    def __init__(self, *fileobjs):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   110
        for f in fileobjs:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   111
            if not util.safehasattr(f, 'length'):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   112
                raise ValueError(
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   113
                    '_multifile only supports file objects that '
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   114
                    'have a length but this one does not:', type(f), f)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   115
        self._fileobjs = fileobjs
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   116
        self._index = 0
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   117
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   118
    @property
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   119
    def length(self):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   120
        return sum(f.length for f in self._fileobjs)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   121
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   122
    def read(self, amt=None):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   123
        if amt <= 0:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   124
            return ''.join(f.read() for f in self._fileobjs)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   125
        parts = []
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   126
        while amt and self._index < len(self._fileobjs):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   127
            parts.append(self._fileobjs[self._index].read(amt))
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   128
            got = len(parts[-1])
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   129
            if got < amt:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   130
                self._index += 1
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   131
            amt -= got
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   132
        return ''.join(parts)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   133
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   134
    def seek(self, offset, whence=os.SEEK_SET):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   135
        if whence != os.SEEK_SET:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   136
            raise NotImplementedError(
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   137
                '_multifile does not support anything other'
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   138
                ' than os.SEEK_SET for whence on seek()')
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   139
        if offset != 0:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   140
            raise NotImplementedError(
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   141
                '_multifile only supports seeking to start, but that '
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   142
                'could be fixed if you need it')
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   143
        for f in self._fileobjs:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   144
            f.seek(0)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   145
        self._index = 0
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
   146
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   147
def makev1commandrequest(ui, requestbuilder, caps, capablefn,
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   148
                         repobaseurl, cmd, args):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   149
    """Make an HTTP request to run a command for a version 1 client.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   150
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   151
    ``caps`` is a set of known server capabilities. The value may be
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   152
    None if capabilities are not yet known.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   153
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   154
    ``capablefn`` is a function to evaluate a capability.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   155
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   156
    ``cmd``, ``args``, and ``data`` define the command, its arguments, and
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   157
    raw data to pass to it.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   158
    """
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   159
    if cmd == 'pushkey':
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   160
        args['data'] = ''
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   161
    data = args.pop('data', None)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   162
    headers = args.pop('headers', {})
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   163
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   164
    ui.debug("sending %s command\n" % cmd)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   165
    q = [('cmd', cmd)]
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   166
    headersize = 0
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   167
    # Important: don't use self.capable() here or else you end up
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   168
    # with infinite recursion when trying to look up capabilities
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   169
    # for the first time.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   170
    postargsok = caps is not None and 'httppostargs' in caps
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   171
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   172
    # Send arguments via POST.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   173
    if postargsok and args:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   174
        strargs = urlreq.urlencode(sorted(args.items()))
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   175
        if not data:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   176
            data = strargs
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   177
        else:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   178
            if isinstance(data, bytes):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   179
                i = io.BytesIO(data)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   180
                i.length = len(data)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   181
                data = i
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   182
            argsio = io.BytesIO(strargs)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   183
            argsio.length = len(strargs)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   184
            data = _multifile(argsio, data)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   185
        headers[r'X-HgArgs-Post'] = len(strargs)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   186
    elif args:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   187
        # Calling self.capable() can infinite loop if we are calling
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   188
        # "capabilities". But that command should never accept wire
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   189
        # protocol arguments. So this should never happen.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   190
        assert cmd != 'capabilities'
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   191
        httpheader = capablefn('httpheader')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   192
        if httpheader:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   193
            headersize = int(httpheader.split(',', 1)[0])
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   194
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   195
        # Send arguments via HTTP headers.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   196
        if headersize > 0:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   197
            # The headers can typically carry more data than the URL.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   198
            encargs = urlreq.urlencode(sorted(args.items()))
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   199
            for header, value in encodevalueinheaders(encargs, 'X-HgArg',
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   200
                                                      headersize):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   201
                headers[header] = value
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   202
        # Send arguments via query string (Mercurial <1.9).
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   203
        else:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   204
            q += sorted(args.items())
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   205
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   206
    qs = '?%s' % urlreq.urlencode(q)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   207
    cu = "%s%s" % (repobaseurl, qs)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   208
    size = 0
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   209
    if util.safehasattr(data, 'length'):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   210
        size = data.length
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   211
    elif data is not None:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   212
        size = len(data)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   213
    if data is not None and r'Content-Type' not in headers:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   214
        headers[r'Content-Type'] = r'application/mercurial-0.1'
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   215
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   216
    # Tell the server we accept application/mercurial-0.2 and multiple
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   217
    # compression formats if the server is capable of emitting those
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   218
    # payloads.
37556
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
   219
    # Note: Keep this set empty by default, as client advertisement of
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
   220
    # protocol parameters should only occur after the handshake.
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
   221
    protoparams = set()
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   222
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   223
    mediatypes = set()
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   224
    if caps is not None:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   225
        mt = capablefn('httpmediatype')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   226
        if mt:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   227
            protoparams.add('0.1')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   228
            mediatypes = set(mt.split(','))
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   229
37556
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
   230
        protoparams.add('partial-pull')
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
   231
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   232
    if '0.2tx' in mediatypes:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   233
        protoparams.add('0.2')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   234
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   235
    if '0.2tx' in mediatypes and capablefn('compression'):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   236
        # We /could/ compare supported compression formats and prune
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   237
        # non-mutually supported or error if nothing is mutually supported.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   238
        # For now, send the full list to the server and have it error.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   239
        comps = [e.wireprotosupport().name for e in
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   240
                 util.compengines.supportedwireengines(util.CLIENTROLE)]
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   241
        protoparams.add('comp=%s' % ','.join(comps))
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   242
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   243
    if protoparams:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   244
        protoheaders = encodevalueinheaders(' '.join(sorted(protoparams)),
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   245
                                            'X-HgProto',
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   246
                                            headersize or 1024)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   247
        for header, value in protoheaders:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   248
            headers[header] = value
37555
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
   249
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
   250
    varyheaders = []
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
   251
    for header in headers:
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
   252
        if header.lower().startswith(r'x-hg'):
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   253
            varyheaders.append(header)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   254
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   255
    if varyheaders:
37555
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
   256
        headers[r'Vary'] = r','.join(sorted(varyheaders))
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   257
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   258
    req = requestbuilder(pycompat.strurl(cu), data, headers)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   259
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   260
    if data is not None:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   261
        ui.debug("sending %d bytes\n" % size)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   262
        req.add_unredirected_header(r'Content-Length', r'%d' % size)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   263
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   264
    return req, cu, qs
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   265
37738
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   266
def _reqdata(req):
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   267
    """Get request data, if any. If no data, returns None."""
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   268
    if pycompat.ispy3:
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   269
        return req.data
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   270
    if not req.has_data():
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   271
        return None
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   272
    return req.get_data()
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   273
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   274
def sendrequest(ui, opener, req):
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   275
    """Send a prepared HTTP request.
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   276
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   277
    Returns the response object.
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   278
    """
38033
13b2812cff2b httppeer: declare 'dbg' at the function level
Boris Feld <boris.feld@octobus.net>
parents: 38032
diff changeset
   279
    dbg = ui.debug
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   280
    if (ui.debugflag
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   281
        and ui.configbool('devel', 'debug.peer-request')):
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   282
        line = 'devel-peer-request: %s\n'
37736
e10b695b9c41 httppeer: fix debug prints to work on Python 3
Augie Fackler <augie@google.com>
parents: 37719
diff changeset
   283
        dbg(line % '%s %s' % (pycompat.bytesurl(req.get_method()),
e10b695b9c41 httppeer: fix debug prints to work on Python 3
Augie Fackler <augie@google.com>
parents: 37719
diff changeset
   284
                              pycompat.bytesurl(req.get_full_url())))
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   285
        hgargssize = None
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   286
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   287
        for header, value in sorted(req.header_items()):
37737
6cb7e3b91883 httppeer: no matter what Python 3 might think, http headers are bytes
Augie Fackler <augie@google.com>
parents: 37736
diff changeset
   288
            header = pycompat.bytesurl(header)
6cb7e3b91883 httppeer: no matter what Python 3 might think, http headers are bytes
Augie Fackler <augie@google.com>
parents: 37736
diff changeset
   289
            value = pycompat.bytesurl(value)
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   290
            if header.startswith('X-hgarg-'):
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   291
                if hgargssize is None:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   292
                    hgargssize = 0
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   293
                hgargssize += len(value)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   294
            else:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   295
                dbg(line % '  %s %s' % (header, value))
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   296
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   297
        if hgargssize is not None:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   298
            dbg(line % '  %d bytes of commands arguments in headers'
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   299
                % hgargssize)
37738
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   300
        data = _reqdata(req)
a1f785148097 httppeer: work around API differences on urllib Request objects
Augie Fackler <augie@google.com>
parents: 37737
diff changeset
   301
        if data is not None:
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   302
            length = getattr(data, 'length', None)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   303
            if length is None:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   304
                length = len(data)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   305
            dbg(line % '  %d bytes of data' % length)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   306
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   307
        start = util.timer()
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   308
38502
2279d90eed9a httppeer: fix use of uninitialized variable with devel logging
Martin von Zweigbergk <martinvonz@google.com>
parents: 38239
diff changeset
   309
    res = None
37550
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   310
    try:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   311
        res = opener.open(req)
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   312
    except urlerr.httperror as inst:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   313
        if inst.code == 401:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   314
            raise error.Abort(_('authorization failed'))
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   315
        raise
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   316
    except httplib.HTTPException as inst:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   317
        ui.debug('http error requesting %s\n' %
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   318
                 util.hidepassword(req.get_full_url()))
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   319
        ui.traceback()
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   320
        raise IOError(None, inst)
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   321
    finally:
38032
f9dc1d5b676b httppeer: properly gate debug usage behind debug flag check
Boris Feld <boris.feld@octobus.net>
parents: 37832
diff changeset
   322
        if ui.debugflag and ui.configbool('devel', 'debug.peer-request'):
38502
2279d90eed9a httppeer: fix use of uninitialized variable with devel logging
Martin von Zweigbergk <martinvonz@google.com>
parents: 38239
diff changeset
   323
            code = res.code if res else -1
37736
e10b695b9c41 httppeer: fix debug prints to work on Python 3
Augie Fackler <augie@google.com>
parents: 37719
diff changeset
   324
            dbg(line % '  finished in %.4f seconds (%d)'
38502
2279d90eed9a httppeer: fix use of uninitialized variable with devel logging
Martin von Zweigbergk <martinvonz@google.com>
parents: 38239
diff changeset
   325
                % (util.timer() - start, code))
37550
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   326
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   327
    # Insert error handlers for common I/O failures.
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   328
    _wraphttpresponse(res)
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   329
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   330
    return res
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
   331
37832
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   332
class RedirectedRepoError(error.RepoError):
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   333
    def __init__(self, msg, respurl):
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   334
        super(RedirectedRepoError, self).__init__(msg)
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   335
        self.respurl = respurl
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   336
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   337
def parsev1commandresponse(ui, baseurl, requrl, qs, resp, compressible,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   338
                           allowcbor=False):
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   339
    # record the url we got redirected to
37832
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   340
    redirected = False
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   341
    respurl = pycompat.bytesurl(resp.geturl())
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   342
    if respurl.endswith(qs):
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   343
        respurl = respurl[:-len(qs)]
37832
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   344
        qsdropped = False
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   345
    else:
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   346
        qsdropped = True
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   347
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   348
    if baseurl.rstrip('/') != respurl.rstrip('/'):
37832
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   349
        redirected = True
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   350
        if not ui.quiet:
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   351
            ui.warn(_('real URL is %s\n') % respurl)
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   352
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   353
    try:
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   354
        proto = pycompat.bytesurl(resp.getheader(r'content-type', r''))
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   355
    except AttributeError:
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   356
        proto = pycompat.bytesurl(resp.headers.get(r'content-type', r''))
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   357
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   358
    safeurl = util.hidepassword(baseurl)
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   359
    if proto.startswith('application/hg-error'):
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   360
        raise error.OutOfBandError(resp.read())
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   361
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   362
    # Pre 1.0 versions of Mercurial used text/plain and
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   363
    # application/hg-changegroup. We don't support such old servers.
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   364
    if not proto.startswith('application/mercurial-'):
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   365
        ui.debug("requested URL: '%s'\n" % util.hidepassword(requrl))
37832
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   366
        msg = _("'%s' does not appear to be an hg repository:\n"
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   367
                "---%%<--- (%s)\n%s\n---%%<---\n") % (
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   368
            safeurl, proto or 'no content-type', resp.read(1024))
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   369
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   370
        # Some servers may strip the query string from the redirect. We
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   371
        # raise a special error type so callers can react to this specially.
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   372
        if redirected and qsdropped:
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   373
            raise RedirectedRepoError(msg, respurl)
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   374
        else:
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   375
            raise error.RepoError(msg)
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   376
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   377
    try:
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   378
        subtype = proto.split('-', 1)[1]
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   379
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   380
        # Unless we end up supporting CBOR in the legacy wire protocol,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   381
        # this should ONLY be encountered for the initial capabilities
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   382
        # request during handshake.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   383
        if subtype == 'cbor':
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   384
            if allowcbor:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   385
                return respurl, proto, resp
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   386
            else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   387
                raise error.RepoError(_('unexpected CBOR response from '
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   388
                                        'server'))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   389
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   390
        version_info = tuple([int(n) for n in subtype.split('.')])
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   391
    except ValueError:
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   392
        raise error.RepoError(_("'%s' sent a broken Content-Type "
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   393
                                "header (%s)") % (safeurl, proto))
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   394
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   395
    # TODO consider switching to a decompression reader that uses
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   396
    # generators.
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   397
    if version_info == (0, 1):
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   398
        if compressible:
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   399
            resp = util.compengines['zlib'].decompressorreader(resp)
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   400
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   401
    elif version_info == (0, 2):
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   402
        # application/mercurial-0.2 always identifies the compression
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   403
        # engine in the payload header.
39484
98995b689e03 httppeer: use util.readexactly() to abort on incomplete responses
Anton Shestakov <av6@dwimlabs.net>
parents: 39483
diff changeset
   404
        elen = struct.unpack('B', util.readexactly(resp, 1))[0]
98995b689e03 httppeer: use util.readexactly() to abort on incomplete responses
Anton Shestakov <av6@dwimlabs.net>
parents: 39483
diff changeset
   405
        ename = util.readexactly(resp, elen)
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   406
        engine = util.compengines.forwiretype(ename)
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   407
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   408
        resp = engine.decompressorreader(resp)
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   409
    else:
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   410
        raise error.RepoError(_("'%s' uses newer protocol %s") %
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   411
                              (safeurl, subtype))
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   412
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   413
    return respurl, proto, resp
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
   414
37614
a81d02ea65db wireproto: move version 1 peer functionality to standalone module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37611
diff changeset
   415
class httppeer(wireprotov1peer.wirepeer):
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   416
    def __init__(self, ui, path, url, opener, requestbuilder, caps):
37321
e826fe7a08c7 peer: make ui an attribute
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37320
diff changeset
   417
        self.ui = ui
33705
73fd395ee29e httppeer: make several instance attributes internal (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33704
diff changeset
   418
        self._path = path
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   419
        self._url = url
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   420
        self._caps = caps
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   421
        self._urlopener = opener
37547
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
   422
        self._requestbuilder = requestbuilder
4516
96d8a56d4ef9 Removed trailing whitespace and tabs from python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4369
diff changeset
   423
7752
998fc8f62539 close sockets on httprepository deletion (issue1487)
Steve Borho <steve@borho.org>
parents: 7641
diff changeset
   424
    def __del__(self):
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   425
        for h in self._urlopener.handlers:
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   426
            h.close()
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   427
            getattr(h, "close_all", lambda: None)()
7752
998fc8f62539 close sockets on httprepository deletion (issue1487)
Steve Borho <steve@borho.org>
parents: 7641
diff changeset
   428
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37006
diff changeset
   429
    # Begin of ipeerconnection interface.
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   430
2673
109a22f5434a hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2612
diff changeset
   431
    def url(self):
33705
73fd395ee29e httppeer: make several instance attributes internal (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33704
diff changeset
   432
        return self._path
2673
109a22f5434a hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2612
diff changeset
   433
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   434
    def local(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   435
        return None
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   436
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   437
    def peer(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   438
        return self
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   439
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   440
    def canpush(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   441
        return True
2442
c660691fb45d http: query server for capabilities
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2439
diff changeset
   442
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   443
    def close(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   444
        pass
13603
395a84f78736 httprepo: use caps instead of between for compat check
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 13555
diff changeset
   445
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37006
diff changeset
   446
    # End of ipeerconnection interface.
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   447
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37006
diff changeset
   448
    # Begin of ipeercommands interface.
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   449
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   450
    def capabilities(self):
33705
73fd395ee29e httppeer: make several instance attributes internal (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33704
diff changeset
   451
        return self._caps
2442
c660691fb45d http: query server for capabilities
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2439
diff changeset
   452
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37006
diff changeset
   453
    # End of ipeercommands interface.
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
   454
30464
e16e234b9ca3 httppeer: do decompression inside _callstream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30241
diff changeset
   455
    def _callstream(self, cmd, _compressible=False, **args):
35359
98bc4c43f570 py3: handle keyword arguments correctly in httppeer.py
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35197
diff changeset
   456
        args = pycompat.byteskwargs(args)
36218
e4ccd7a69f77 httppeer: change logic around argument handling
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35884
diff changeset
   457
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   458
        req, cu, qs = makev1commandrequest(self.ui, self._requestbuilder,
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   459
                                           self._caps, self.capable,
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
   460
                                           self._url, cmd, args)
30763
a520aefb96f1 httppeer: advertise and support application/mercurial-0.2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
   461
37550
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
   462
        resp = sendrequest(self.ui, self._urlopener, req)
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
   463
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   464
        self._url, ct, resp = parsev1commandresponse(self.ui, self._url, cu, qs,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   465
                                                     resp, _compressible)
30464
e16e234b9ca3 httppeer: do decompression inside _callstream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30241
diff changeset
   466
752
c693eafd5967 Simplify content type checking
mpm@selenic.com
parents: 751
diff changeset
   467
        return resp
60
e32fdbd97839 Add hg:// protocol
mpm@selenic.com
parents: 56
diff changeset
   468
11589
e8d22fe2ddab protocol: clean up call-like functions in http and ssh clients
Matt Mackall <mpm@selenic.com>
parents: 11588
diff changeset
   469
    def _call(self, cmd, **args):
e8d22fe2ddab protocol: clean up call-like functions in http and ssh clients
Matt Mackall <mpm@selenic.com>
parents: 11588
diff changeset
   470
        fp = self._callstream(cmd, **args)
2435
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
   471
        try:
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
   472
            return fp.read()
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
   473
        finally:
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
   474
            # if using keepalive, allow connection to be reused
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
   475
            fp.close()
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
   476
11592
26e0782b8380 protocol: unify client unbundle support
Matt Mackall <mpm@selenic.com>
parents: 11591
diff changeset
   477
    def _callpush(self, cmd, cg, **args):
2465
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
   478
        # have to stream bundle to a temp file because we do not have
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
   479
        # http 1.1 chunked transfer.
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
   480
3662
f4dc02d7fb71 unduplicate bundle writing code from httprepo
Matt Mackall <mpm@selenic.com>
parents: 3661
diff changeset
   481
        types = self.capable('unbundle')
3703
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
   482
        try:
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
   483
            types = types.split(',')
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
   484
        except AttributeError:
14060
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
   485
            # servers older than d1b16a746db6 will send 'unbundle' as a
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
   486
            # boolean capability. They only support headerless/uncompressed
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
   487
            # bundles.
3703
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
   488
            types = [""]
14060
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
   489
        for x in types:
28666
ae53ecc47414 bundle: move writebundle() from changegroup.py to bundle2.py (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28530
diff changeset
   490
            if x in bundle2.bundletypes:
14060
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
   491
                type = x
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
   492
                break
3613
cbf352b9a3cd Client support for hgweb unbundle with versions.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3609
diff changeset
   493
28666
ae53ecc47414 bundle: move writebundle() from changegroup.py to bundle2.py (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28530
diff changeset
   494
        tempname = bundle2.writebundle(self.ui, cg, None, type)
14244
e7525a555a64 url: use new http support if requested by the user
Augie Fackler <durin42@gmail.com>
parents: 14149
diff changeset
   495
        fp = httpconnection.httpsendfile(self.ui, tempname, "rb")
36297
a59ff82154b8 httppeer: headers are native strings
Augie Fackler <augie@google.com>
parents: 36270
diff changeset
   496
        headers = {r'Content-Type': r'application/mercurial-0.1'}
11592
26e0782b8380 protocol: unify client unbundle support
Matt Mackall <mpm@selenic.com>
parents: 11591
diff changeset
   497
2465
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
   498
        try:
25085
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
   499
            r = self._call(cmd, data=fp, headers=headers, **args)
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
   500
            vals = r.split('\n', 1)
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
   501
            if len(vals) < 2:
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
   502
                raise error.ResponseError(_("unexpected response:"), r)
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
   503
            return vals
36430
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
   504
        except urlerr.httperror:
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
   505
            # Catch and re-raise these so we don't try and treat them
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
   506
            # like generic socket errors. They lack any values in
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
   507
            # .args on Python 3 which breaks our socket.error block.
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
   508
            raise
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25500
diff changeset
   509
        except socket.error as err:
25085
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
   510
            if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25954
diff changeset
   511
                raise error.Abort(_('push failed: %s') % err.args[1])
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25954
diff changeset
   512
            raise error.Abort(err.args[1])
2465
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
   513
        finally:
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
   514
            fp.close()
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
   515
            os.unlink(tempname)
2439
e8c4f3d3df8c extend network protocol to stop clients from locking servers
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2435
diff changeset
   516
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   517
    def _calltwowaystream(self, cmd, fp, **args):
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   518
        fh = None
23086
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
   519
        fp_ = None
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   520
        filename = None
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   521
        try:
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   522
            # dump bundle to disk
38164
aac4be30e250 py3: wrap tempfile.mkstemp() to use bytes path
Yuya Nishihara <yuya@tcha.org>
parents: 37832
diff changeset
   523
            fd, filename = pycompat.mkstemp(prefix="hg-bundle-", suffix=".hg")
36835
5bc7ff103081 py3: use r'' instead of sysstr('') to get around code transformer
Yuya Nishihara <yuya@tcha.org>
parents: 36430
diff changeset
   524
            fh = os.fdopen(fd, r"wb")
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   525
            d = fp.read(4096)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   526
            while d:
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   527
                fh.write(d)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   528
                d = fp.read(4096)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   529
            fh.close()
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   530
            # start http push
23086
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
   531
            fp_ = httpconnection.httpsendfile(self.ui, filename, "rb")
36297
a59ff82154b8 httppeer: headers are native strings
Augie Fackler <augie@google.com>
parents: 36270
diff changeset
   532
            headers = {r'Content-Type': r'application/mercurial-0.1'}
23086
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
   533
            return self._callstream(cmd, data=fp_, headers=headers, **args)
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   534
        finally:
23086
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
   535
            if fp_ is not None:
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
   536
                fp_.close()
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   537
            if fh is not None:
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   538
                fh.close()
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   539
                os.unlink(filename)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
   540
20905
167047ba3cfa wireproto: drop the _decompress method in favor a new call type
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 18742
diff changeset
   541
    def _callcompressable(self, cmd, **args):
30464
e16e234b9ca3 httppeer: do decompression inside _callstream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30241
diff changeset
   542
        return self._callstream(cmd, _compressible=True, **args)
11370
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 11153
diff changeset
   543
21188
d36440d84328 httppeer: reintroduce _abort that accidentally was removed in 167047ba3cfa
Mads Kiilerich <madski@unity3d.com>
parents: 21074
diff changeset
   544
    def _abort(self, exception):
d36440d84328 httppeer: reintroduce _abort that accidentally was removed in 167047ba3cfa
Mads Kiilerich <madski@unity3d.com>
parents: 21074
diff changeset
   545
        raise exception
d36440d84328 httppeer: reintroduce _abort that accidentally was removed in 167047ba3cfa
Mads Kiilerich <madski@unity3d.com>
parents: 21074
diff changeset
   546
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   547
def sendv2request(ui, opener, requestbuilder, apiurl, permission, requests):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   548
    reactor = wireprotoframing.clientreactor(hasmultiplesend=False,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   549
                                             buffersends=True)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   550
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   551
    handler = wireprotov2peer.clienthandler(ui, reactor)
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   552
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   553
    url = '%s/%s' % (apiurl, permission)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   554
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   555
    if len(requests) > 1:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   556
        url += '/multirequest'
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   557
    else:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   558
        url += '/%s' % requests[0][0]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   559
39436
3fe028b657bf httppeer: log commands for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38783
diff changeset
   560
    ui.debug('sending %d commands\n' % len(requests))
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   561
    for command, args, f in requests:
39436
3fe028b657bf httppeer: log commands for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38783
diff changeset
   562
        ui.debug('sending command %s: %s\n' % (
3fe028b657bf httppeer: log commands for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38783
diff changeset
   563
            command, stringutil.pprint(args, indent=2)))
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   564
        assert not list(handler.callcommand(command, args, f))
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   565
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   566
    # TODO stream this.
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   567
    body = b''.join(map(bytes, handler.flushcommands()))
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   568
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   569
    # TODO modify user-agent to reflect v2
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   570
    headers = {
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   571
        r'Accept': wireprotov2server.FRAMINGTYPE,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   572
        r'Content-Type': wireprotov2server.FRAMINGTYPE,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   573
    }
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   574
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   575
    req = requestbuilder(pycompat.strurl(url), body, headers)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   576
    req.add_unredirected_header(r'Content-Length', r'%d' % len(body))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   577
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   578
    try:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   579
        res = opener.open(req)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   580
    except urlerr.httperror as e:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   581
        if e.code == 401:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   582
            raise error.Abort(_('authorization failed'))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   583
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   584
        raise
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   585
    except httplib.HTTPException as e:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   586
        ui.traceback()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   587
        raise IOError(None, e)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   588
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   589
    return handler, res
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   590
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   591
class queuedcommandfuture(pycompat.futures.Future):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   592
    """Wraps result() on command futures to trigger submission on call."""
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   593
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   594
    def result(self, timeout=None):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   595
        if self.done():
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   596
            return pycompat.futures.Future.result(self, timeout)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   597
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   598
        self._peerexecutor.sendcommands()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   599
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   600
        # sendcommands() will restore the original __class__ and self.result
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   601
        # will resolve to Future.result.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   602
        return self.result(timeout)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   603
37810
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
   604
@interfaceutil.implementer(repository.ipeercommandexecutor)
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   605
class httpv2executor(object):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   606
    def __init__(self, ui, opener, requestbuilder, apiurl, descriptor):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   607
        self._ui = ui
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   608
        self._opener = opener
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   609
        self._requestbuilder = requestbuilder
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   610
        self._apiurl = apiurl
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   611
        self._descriptor = descriptor
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   612
        self._sent = False
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   613
        self._closed = False
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   614
        self._neededpermissions = set()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   615
        self._calls = []
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   616
        self._futures = weakref.WeakSet()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   617
        self._responseexecutor = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   618
        self._responsef = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   619
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   620
    def __enter__(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   621
        return self
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   622
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   623
    def __exit__(self, exctype, excvalue, exctb):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   624
        self.close()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   625
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   626
    def callcommand(self, command, args):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   627
        if self._sent:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   628
            raise error.ProgrammingError('callcommand() cannot be used after '
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   629
                                         'commands are sent')
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   630
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   631
        if self._closed:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   632
            raise error.ProgrammingError('callcommand() cannot be used after '
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   633
                                         'close()')
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   634
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   635
        # The service advertises which commands are available. So if we attempt
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   636
        # to call an unknown command or pass an unknown argument, we can screen
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   637
        # for this.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   638
        if command not in self._descriptor['commands']:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   639
            raise error.ProgrammingError(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   640
                'wire protocol command %s is not available' % command)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   641
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   642
        cmdinfo = self._descriptor['commands'][command]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   643
        unknownargs = set(args.keys()) - set(cmdinfo.get('args', {}))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   644
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   645
        if unknownargs:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   646
            raise error.ProgrammingError(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   647
                'wire protocol command %s does not accept argument: %s' % (
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   648
                    command, ', '.join(sorted(unknownargs))))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   649
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   650
        self._neededpermissions |= set(cmdinfo['permissions'])
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   652
        # TODO we /could/ also validate types here, since the API descriptor
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   653
        # includes types...
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   654
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   655
        f = pycompat.futures.Future()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   656
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   657
        # Monkeypatch it so result() triggers sendcommands(), otherwise result()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   658
        # could deadlock.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   659
        f.__class__ = queuedcommandfuture
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   660
        f._peerexecutor = self
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   661
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   662
        self._futures.add(f)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   663
        self._calls.append((command, args, f))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   664
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   665
        return f
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   666
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   667
    def sendcommands(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   668
        if self._sent:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   669
            return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   670
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   671
        if not self._calls:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   672
            return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   673
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   674
        self._sent = True
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   675
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   676
        # Unhack any future types so caller sees a clean type and so we
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   677
        # break reference cycle.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   678
        for f in self._futures:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   679
            if isinstance(f, queuedcommandfuture):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   680
                f.__class__ = pycompat.futures.Future
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   681
                f._peerexecutor = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   682
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   683
        # Mark the future as running and filter out cancelled futures.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   684
        calls = [(command, args, f)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   685
                 for command, args, f in self._calls
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   686
                 if f.set_running_or_notify_cancel()]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   687
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   688
        # Clear out references, prevent improper object usage.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   689
        self._calls = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   690
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   691
        if not calls:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   692
            return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   693
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   694
        permissions = set(self._neededpermissions)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   695
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   696
        if 'push' in permissions and 'pull' in permissions:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   697
            permissions.remove('pull')
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   698
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   699
        if len(permissions) > 1:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   700
            raise error.RepoError(_('cannot make request requiring multiple '
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   701
                                    'permissions: %s') %
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   702
                                  _(', ').join(sorted(permissions)))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   703
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   704
        permission = {
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   705
            'push': 'rw',
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   706
            'pull': 'ro',
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   707
        }[permissions.pop()]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   708
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   709
        handler, resp = sendv2request(
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   710
            self._ui, self._opener, self._requestbuilder, self._apiurl,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   711
            permission, calls)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   712
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   713
        # TODO we probably want to validate the HTTP code, media type, etc.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   714
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   715
        self._responseexecutor = pycompat.futures.ThreadPoolExecutor(1)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   716
        self._responsef = self._responseexecutor.submit(self._handleresponse,
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   717
                                                        handler, resp)
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   718
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   719
    def close(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   720
        if self._closed:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   721
            return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   722
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   723
        self.sendcommands()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   724
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   725
        self._closed = True
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   726
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   727
        if not self._responsef:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   728
            return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   729
39437
3c6f7eebc010 httppeer: add TODO about delayed handling of ^C
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39436
diff changeset
   730
        # TODO ^C here may not result in immediate program termination.
3c6f7eebc010 httppeer: add TODO about delayed handling of ^C
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39436
diff changeset
   731
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   732
        try:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   733
            self._responsef.result()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   734
        finally:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   735
            self._responseexecutor.shutdown(wait=True)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   736
            self._responsef = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   737
            self._responseexecutor = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   738
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   739
            # If any of our futures are still in progress, mark them as
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   740
            # errored, otherwise a result() could wait indefinitely.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   741
            for f in self._futures:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   742
                if not f.done():
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   743
                    f.set_exception(error.ResponseError(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   744
                        _('unfulfilled command response')))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   745
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   746
            self._futures = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   747
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   748
    def _handleresponse(self, handler, resp):
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   749
        # Called in a thread to read the response.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   750
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   751
        while handler.readframe(resp):
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   752
            pass
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   753
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   754
# TODO implement interface for version 2 peers
37810
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
   755
@interfaceutil.implementer(repository.ipeerconnection,
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
   756
                           repository.ipeercapabilities,
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
   757
                           repository.ipeerrequests)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   758
class httpv2peer(object):
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   759
    def __init__(self, ui, repourl, apipath, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   760
                 apidescriptor):
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   761
        self.ui = ui
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   762
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   763
        if repourl.endswith('/'):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   764
            repourl = repourl[:-1]
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   765
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   766
        self._url = repourl
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   767
        self._apipath = apipath
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   768
        self._apiurl = '%s/%s' % (repourl, apipath)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   769
        self._opener = opener
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   770
        self._requestbuilder = requestbuilder
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   771
        self._descriptor = apidescriptor
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   772
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   773
    # Start of ipeerconnection.
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   774
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   775
    def url(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   776
        return self._url
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   777
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   778
    def local(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   779
        return None
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   780
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   781
    def peer(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   782
        return self
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   783
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   784
    def canpush(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   785
        # TODO change once implemented.
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   786
        return False
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   787
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   788
    def close(self):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   789
        pass
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   790
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   791
    # End of ipeerconnection.
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   792
37611
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   793
    # Start of ipeercapabilities.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   794
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   795
    def capable(self, name):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   796
        # The capabilities used internally historically map to capabilities
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   797
        # advertised from the "capabilities" wire protocol command. However,
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   798
        # version 2 of that command works differently.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   799
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   800
        # Maps to commands that are available.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   801
        if name in ('branchmap', 'getbundle', 'known', 'lookup', 'pushkey'):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   802
            return True
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   803
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   804
        # Other concepts.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   805
        if name in ('bundle2',):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   806
            return True
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   807
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   808
        return False
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   809
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   810
    def requirecap(self, name, purpose):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   811
        if self.capable(name):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   812
            return
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   813
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   814
        raise error.CapabilityError(
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   815
            _('cannot %s; client or remote repository does not support the %r '
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   816
              'capability') % (purpose, name))
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   817
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   818
    # End of ipeercapabilities.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   819
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   820
    def _call(self, name, **args):
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   821
        with self.commandexecutor() as e:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   822
            return e.callcommand(name, args).result()
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
   823
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   824
    def commandexecutor(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   825
        return httpv2executor(self.ui, self._opener, self._requestbuilder,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   826
                              self._apiurl, self._descriptor)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   827
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   828
# Registry of API service names to metadata about peers that handle it.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   829
#
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   830
# The following keys are meaningful:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   831
#
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   832
# init
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   833
#    Callable receiving (ui, repourl, servicepath, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   834
#                        apidescriptor) to create a peer.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   835
#
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   836
# priority
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   837
#    Integer priority for the service. If we could choose from multiple
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   838
#    services, we choose the one with the highest priority.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   839
API_PEERS = {
37644
77c9ee77687c wireproto: rename HTTPV2 so it less like HTTP/2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37614
diff changeset
   840
    wireprototypes.HTTP_WIREPROTO_V2: {
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   841
        'init': httpv2peer,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   842
        'priority': 50,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   843
    },
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   844
}
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   845
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   846
def performhandshake(ui, url, opener, requestbuilder):
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   847
    # The handshake is a request to the capabilities command.
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   848
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   849
    caps = None
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   850
    def capable(x):
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   851
        raise error.ProgrammingError('should not be called')
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   852
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   853
    args = {}
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   854
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   855
    # The client advertises support for newer protocols by adding an
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   856
    # X-HgUpgrade-* header with a list of supported APIs and an
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   857
    # X-HgProto-* header advertising which serializing formats it supports.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   858
    # We only support the HTTP version 2 transport and CBOR responses for
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   859
    # now.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   860
    advertisev2 = ui.configbool('experimental', 'httppeer.advertise-v2')
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   861
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   862
    if advertisev2:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   863
        args['headers'] = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   864
            r'X-HgProto-1': r'cbor',
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   865
        }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   866
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   867
        args['headers'].update(
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   868
            encodevalueinheaders(' '.join(sorted(API_PEERS)),
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   869
                                 'X-HgUpgrade',
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   870
                                 # We don't know the header limit this early.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   871
                                 # So make it small.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   872
                                 1024))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   873
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   874
    req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps,
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   875
                                           capable, url, 'capabilities',
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   876
                                           args)
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   877
    resp = sendrequest(ui, opener, req)
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   878
37832
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   879
    # The server may redirect us to the repo root, stripping the
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   880
    # ?cmd=capabilities query string from the URL. The server would likely
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   881
    # return HTML in this case and ``parsev1commandresponse()`` would raise.
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   882
    # We catch this special case and re-issue the capabilities request against
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   883
    # the new URL.
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   884
    #
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   885
    # We should ideally not do this, as a redirect that drops the query
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   886
    # string from the URL is arguably a server bug. (Garbage in, garbage out).
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   887
    # However,  Mercurial clients for several years appeared to handle this
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   888
    # issue without behavior degradation. And according to issue 5860, it may
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   889
    # be a longstanding bug in some server implementations. So we allow a
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   890
    # redirect that drops the query string to "just work."
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   891
    try:
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   892
        respurl, ct, resp = parsev1commandresponse(ui, url, requrl, qs, resp,
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   893
                                                   compressible=False,
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   894
                                                   allowcbor=advertisev2)
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   895
    except RedirectedRepoError as e:
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   896
        req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps,
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   897
                                               capable, e.respurl,
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   898
                                               'capabilities', args)
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   899
        resp = sendrequest(ui, opener, req)
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   900
        respurl, ct, resp = parsev1commandresponse(ui, url, requrl, qs, resp,
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   901
                                                   compressible=False,
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   902
                                                   allowcbor=advertisev2)
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   903
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   904
    try:
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   905
        rawdata = resp.read()
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   906
    finally:
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   907
        resp.close()
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   908
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   909
    if not ct.startswith('application/mercurial-'):
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   910
        raise error.ProgrammingError('unexpected content-type: %s' % ct)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   911
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   912
    if advertisev2:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   913
        if ct == 'application/mercurial-cbor':
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   914
            try:
39445
cdb56f295b03 httppeer: use our CBOR decoder
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39437
diff changeset
   915
                info = cborutil.decodeall(rawdata)[0]
cdb56f295b03 httppeer: use our CBOR decoder
Gregory Szorc <gregory.szorc@gmail.com>
parents: 39437
diff changeset
   916
            except cborutil.CBORDecodeError:
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   917
                raise error.Abort(_('error decoding CBOR from remote server'),
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   918
                                  hint=_('try again and consider contacting '
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   919
                                         'the server operator'))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   920
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   921
        # We got a legacy response. That's fine.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   922
        elif ct in ('application/mercurial-0.1', 'application/mercurial-0.2'):
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   923
            info = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   924
                'v1capabilities': set(rawdata.split())
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   925
            }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   926
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   927
        else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   928
            raise error.RepoError(
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   929
                _('unexpected response type from server: %s') % ct)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   930
    else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   931
        info = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   932
            'v1capabilities': set(rawdata.split())
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   933
        }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   934
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   935
    return respurl, info
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   936
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
   937
def makepeer(ui, path, opener=None, requestbuilder=urlreq.request):
37547
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
   938
    """Construct an appropriate HTTP peer instance.
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
   939
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
   940
    ``opener`` is an ``url.opener`` that should be used to establish
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
   941
    connections, perform HTTP requests.
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
   942
37547
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
   943
    ``requestbuilder`` is the type used for constructing HTTP requests.
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
   944
    It exists as an argument so extensions can override the default.
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
   945
    """
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   946
    u = util.url(path)
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   947
    if u.query or u.fragment:
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   948
        raise error.Abort(_('unsupported URL component: "%s"') %
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   949
                          (u.query or u.fragment))
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   950
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   951
    # urllib cannot handle URLs with embedded user or passwd.
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   952
    url, authinfo = u.authinfo()
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   953
    ui.debug('using %s\n' % url)
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   954
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
   955
    opener = opener or urlmod.opener(ui, authinfo)
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   956
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   957
    respurl, info = performhandshake(ui, url, opener, requestbuilder)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   958
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   959
    # Given the intersection of APIs that both we and the server support,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   960
    # sort by their advertised priority and pick the first one.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   961
    #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   962
    # TODO consider making this request-based and interface driven. For
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   963
    # example, the caller could say "I want a peer that does X." It's quite
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   964
    # possible that not all peers would do that. Since we know the service
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   965
    # capabilities, we could filter out services not meeting the
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   966
    # requirements. Possibly by consulting the interfaces defined by the
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   967
    # peer type.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   968
    apipeerchoices = set(info.get('apis', {}).keys()) & set(API_PEERS.keys())
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   969
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   970
    preferredchoices = sorted(apipeerchoices,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   971
                              key=lambda x: API_PEERS[x]['priority'],
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   972
                              reverse=True)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   973
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   974
    for service in preferredchoices:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   975
        apipath = '%s/%s' % (info['apibase'].rstrip('/'), service)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   976
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   977
        return API_PEERS[service]['init'](ui, respurl, apipath, opener,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   978
                                          requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   979
                                          info['apis'][service])
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   980
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   981
    # Failed to construct an API peer. Fall back to legacy.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   982
    return httppeer(ui, path, respurl, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   983
                    info['v1capabilities'])
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   984
37717
0664be4f0c1f hg: pass command intents to repo/peer creation (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37669
diff changeset
   985
def instance(ui, path, create, intents=None):
2740
386f04d6ecb3 clean up hg.py: move repo constructor code into each repo module
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2673
diff changeset
   986
    if create:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25954
diff changeset
   987
        raise error.Abort(_('cannot create new http repository'))
7211
25c0dee16ee0 Autodetect static-http
Matt Mackall <mpm@selenic.com>
parents: 7207
diff changeset
   988
    try:
36959
43815d87c6aa httppeer: alias url as urlmod
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36835
diff changeset
   989
        if path.startswith('https:') and not urlmod.has_https:
36220
874209855f5c httppeer: remove httpspeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36219
diff changeset
   990
            raise error.Abort(_('Python support for SSL and HTTPS '
874209855f5c httppeer: remove httpspeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36219
diff changeset
   991
                                'is not installed'))
35884
197d10e157ce httppeer: remove support for connecting to <0.9.1 servers (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35698
diff changeset
   992
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   993
        inst = makepeer(ui, path)
35884
197d10e157ce httppeer: remove support for connecting to <0.9.1 servers (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35698
diff changeset
   994
7211
25c0dee16ee0 Autodetect static-http
Matt Mackall <mpm@selenic.com>
parents: 7207
diff changeset
   995
        return inst
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25500
diff changeset
   996
    except error.RepoError as httpexception:
14148
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
   997
        try:
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
   998
            r = statichttprepo.instance(ui, "static-" + path, create)
29241
269f7ea08983 httppeer: make a message translatable
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28883
diff changeset
   999
            ui.note(_('(falling back to static-http)\n'))
14148
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
  1000
            return r
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
  1001
        except error.RepoError:
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
  1002
            raise httpexception # use the original http RepoError instead