mercurial/httppeer.py
author Pulkit Goyal <pulkit@yandex-team.ru>
Sun, 26 Aug 2018 20:20:34 +0300
changeset 39356 c8e4eae84808
parent 38783 e7aa113b14f7
child 39436 3fe028b657bf
permissions -rw-r--r--
narrow: add server logic to send cg while widening without ellipsis Before this patch, if you try to widen a narrow clone without ellipsis enabled, it will be broken and the exchange.pull() done by tracked command to widen the clone will be no-op because no custom logic exists for this and server sees that we have all csets and it says `no changes found`. The widening with ellipsis send KILL for existing changegroups and send new changegroups because of the change in ellipsis hash, but we can prevent that in non-ellipsis cases. This patch adds server side logic to send the changegroups for the changesets which are on the client again with filelogs and manifests for the new includes. This is a very starting implementation and we send changegroups and manifests too while we can prevent them. Following things can definitely be improved in the logic this patch adds: 1) Send just the filelogs and treemanifests 2) Send the filelogs only for the additions in the include I tried 1) here but the code is coupled tightly and the way I was able to do that was hacking into the changegroup generation code in a very dirty way, like adding conditionals and preventing the yield. This patch also adds a 'widen' kwarg to prevent other commands except widening to go through that codepath. The test changes demonstrate that the new implementation is correct and fixes things. Differential Revision: https://phab.mercurial-scm.org/D4383
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 _
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
    19
from .thirdparty import (
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
    20
    cbor,
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
    21
)
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    22
from . import (
28666
ae53ecc47414 bundle: move writebundle() from changegroup.py to bundle2.py (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28530
diff changeset
    23
    bundle2,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    24
    error,
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    25
    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
    26
    pycompat,
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
    27
    repository,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    28
    statichttprepo,
36959
43815d87c6aa httppeer: alias url as urlmod
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36835
diff changeset
    29
    url as urlmod,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    30
    util,
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
    31
    wireprotoframing,
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
    32
    wireprototypes,
37614
a81d02ea65db wireproto: move version 1 peer functionality to standalone module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37611
diff changeset
    33
    wireprotov1peer,
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
    34
    wireprotov2peer,
37545
93397c4633f6 wireproto: extract HTTP version 2 code to own module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37544
diff changeset
    35
    wireprotov2server,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    36
)
37810
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
    37
from .utils import (
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
    38
    interfaceutil,
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
    39
)
4678
a814a5b11fff Work around urllib2 digest auth bug with Python < 2.5
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4633
diff changeset
    40
29455
0c741fd6158a py3: conditionalize httplib import
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29241
diff changeset
    41
httplib = util.httplib
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
    42
urlerr = util.urlerr
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
    43
urlreq = util.urlreq
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
    44
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    45
def encodevalueinheaders(value, header, limit):
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    46
    """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
    47
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    48
    ``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
    49
    ``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
    50
    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
    51
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    52
    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
    53
    values as native strings.
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    54
    """
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    55
    # 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
    56
    # 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
    57
    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
    58
    # 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
    59
    # 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
    60
    # 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
    61
    # 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
    62
    # instead of a carriage return.
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    63
    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
    64
    result = []
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    65
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    66
    n = 0
38783
e7aa113b14f7 global: use pycompat.xrange()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38502
diff changeset
    67
    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
    68
        n += 1
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
    69
        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
    70
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    71
    return result
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
    72
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    73
def _wraphttpresponse(resp):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    74
    """Wrap an HTTPResponse with common error handlers.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    75
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    76
    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
    77
    error and messaging.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    78
    """
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    79
    origread = resp.read
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    80
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    81
    class readerproxy(resp.__class__):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    82
        def read(self, size=None):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    83
            try:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    84
                return origread(size)
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    85
            except httplib.IncompleteRead as e:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    86
                # 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
    87
                if e.expected:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    88
                    msg = _('HTTP request error (incomplete response; '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    89
                            'expected %d bytes got %d)') % (e.expected,
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
    90
                                                           len(e.partial))
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.
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   404
        elen = struct.unpack('B', resp.read(1))[0]
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
   405
        ename = resp.read(elen)
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
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   560
    for command, args, f in requests:
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   561
        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
   562
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   563
    # TODO stream this.
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   564
    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
   565
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   566
    # 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
   567
    headers = {
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   568
        r'Accept': wireprotov2server.FRAMINGTYPE,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   569
        r'Content-Type': wireprotov2server.FRAMINGTYPE,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   570
    }
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   571
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   572
    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
   573
    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
   574
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   575
    try:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   576
        res = opener.open(req)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   577
    except urlerr.httperror as e:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   578
        if e.code == 401:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   579
            raise error.Abort(_('authorization failed'))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   580
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   581
        raise
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   582
    except httplib.HTTPException as e:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   583
        ui.traceback()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   584
        raise IOError(None, e)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   585
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   586
    return handler, res
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   587
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   588
class queuedcommandfuture(pycompat.futures.Future):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   589
    """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
   590
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   591
    def result(self, timeout=None):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   592
        if self.done():
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   593
            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
   594
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   595
        self._peerexecutor.sendcommands()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   596
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   597
        # 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
   598
        # will resolve to Future.result.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   599
        return self.result(timeout)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   600
37810
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
   601
@interfaceutil.implementer(repository.ipeercommandexecutor)
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   602
class httpv2executor(object):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   603
    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
   604
        self._ui = ui
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   605
        self._opener = opener
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   606
        self._requestbuilder = requestbuilder
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   607
        self._apiurl = apiurl
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   608
        self._descriptor = descriptor
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   609
        self._sent = False
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   610
        self._closed = False
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   611
        self._neededpermissions = set()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   612
        self._calls = []
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   613
        self._futures = weakref.WeakSet()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   614
        self._responseexecutor = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   615
        self._responsef = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   616
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   617
    def __enter__(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   618
        return self
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 __exit__(self, exctype, excvalue, exctb):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   621
        self.close()
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 callcommand(self, command, args):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   624
        if self._sent:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   625
            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
   626
                                         'commands are sent')
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   627
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   628
        if self._closed:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   629
            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
   630
                                         'close()')
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   631
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   632
        # 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
   633
        # 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
   634
        # for this.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   635
        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
   636
            raise error.ProgrammingError(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   637
                '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
   638
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   639
        cmdinfo = self._descriptor['commands'][command]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   640
        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
   641
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   642
        if unknownargs:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   643
            raise error.ProgrammingError(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   644
                '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
   645
                    command, ', '.join(sorted(unknownargs))))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   646
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   647
        self._neededpermissions |= set(cmdinfo['permissions'])
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   648
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   649
        # 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
   650
        # includes types...
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
        f = pycompat.futures.Future()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   653
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   654
        # 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
   655
        # could deadlock.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   656
        f.__class__ = queuedcommandfuture
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   657
        f._peerexecutor = self
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   658
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   659
        self._futures.add(f)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   660
        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
   661
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   662
        return f
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   663
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   664
    def sendcommands(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   665
        if self._sent:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   666
            return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   667
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   668
        if not self._calls:
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
        self._sent = True
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   672
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   673
        # 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
   674
        # break reference cycle.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   675
        for f in self._futures:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   676
            if isinstance(f, queuedcommandfuture):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   677
                f.__class__ = pycompat.futures.Future
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   678
                f._peerexecutor = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   679
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   680
        # 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
   681
        calls = [(command, args, f)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   682
                 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
   683
                 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
   684
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   685
        # 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
   686
        self._calls = None
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
        if not calls:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   689
            return
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
        permissions = set(self._neededpermissions)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   692
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   693
        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
   694
            permissions.remove('pull')
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 len(permissions) > 1:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   697
            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
   698
                                    'permissions: %s') %
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   699
                                  _(', ').join(sorted(permissions)))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   700
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   701
        permission = {
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   702
            'push': 'rw',
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   703
            'pull': 'ro',
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   704
        }[permissions.pop()]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   705
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   706
        handler, resp = sendv2request(
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   707
            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
   708
            permission, calls)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   709
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   710
        # 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
   711
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   712
        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
   713
        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
   714
                                                        handler, resp)
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   715
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   716
    def close(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   717
        if self._closed:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   718
            return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   719
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   720
        self.sendcommands()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   721
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   722
        self._closed = True
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   723
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   724
        if not self._responsef:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   725
            return
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
        try:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   728
            self._responsef.result()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   729
        finally:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   730
            self._responseexecutor.shutdown(wait=True)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   731
            self._responsef = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   732
            self._responseexecutor = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   733
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   734
            # 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
   735
            # 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
   736
            for f in self._futures:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   737
                if not f.done():
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   738
                    f.set_exception(error.ResponseError(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   739
                        _('unfulfilled command response')))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   740
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   741
            self._futures = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   742
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   743
    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
   744
        # 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
   745
37719
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   746
        while handler.readframe(resp):
a656cba08a04 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37717
diff changeset
   747
            pass
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   748
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   749
# 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
   750
@interfaceutil.implementer(repository.ipeerconnection,
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
   751
                           repository.ipeercapabilities,
856f381ad74b interfaceutil: module to stub out zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37738
diff changeset
   752
                           repository.ipeerrequests)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   753
class httpv2peer(object):
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   754
    def __init__(self, ui, repourl, apipath, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   755
                 apidescriptor):
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   756
        self.ui = ui
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   757
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   758
        if repourl.endswith('/'):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   759
            repourl = repourl[:-1]
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   760
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   761
        self._url = repourl
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   762
        self._apipath = apipath
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   763
        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
   764
        self._opener = opener
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   765
        self._requestbuilder = requestbuilder
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   766
        self._descriptor = apidescriptor
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   767
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   768
    # Start of ipeerconnection.
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   769
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   770
    def url(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   771
        return self._url
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   772
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   773
    def local(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   774
        return None
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   775
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   776
    def peer(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   777
        return self
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   778
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   779
    def canpush(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   780
        # TODO change once implemented.
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   781
        return False
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   782
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   783
    def close(self):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   784
        pass
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   785
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   786
    # End of ipeerconnection.
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
   787
37611
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   788
    # Start of ipeercapabilities.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   789
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   790
    def capable(self, name):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   791
        # 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
   792
        # 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
   793
        # version 2 of that command works differently.
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
        # Maps to commands that are available.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   796
        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
   797
            return True
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   798
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   799
        # Other concepts.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   800
        if name in ('bundle2',):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   801
            return True
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   802
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   803
        return False
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   804
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   805
    def requirecap(self, name, purpose):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   806
        if self.capable(name):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   807
            return
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   808
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   809
        raise error.CapabilityError(
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   810
            _('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
   811
              'capability') % (purpose, name))
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   812
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   813
    # End of ipeercapabilities.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
   814
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   815
    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
   816
        with self.commandexecutor() as e:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   817
            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
   818
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   819
    def commandexecutor(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
   820
        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
   821
                              self._apiurl, self._descriptor)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
   822
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   823
# 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
   824
#
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   825
# The following keys are meaningful:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   826
#
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   827
# init
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   828
#    Callable receiving (ui, repourl, servicepath, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   829
#                        apidescriptor) to create a peer.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   830
#
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   831
# priority
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   832
#    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
   833
#    services, we choose the one with the highest priority.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   834
API_PEERS = {
37644
77c9ee77687c wireproto: rename HTTPV2 so it less like HTTP/2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37614
diff changeset
   835
    wireprototypes.HTTP_WIREPROTO_V2: {
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   836
        'init': httpv2peer,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   837
        'priority': 50,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   838
    },
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   839
}
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   840
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   841
def performhandshake(ui, url, opener, requestbuilder):
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   842
    # 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
   843
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   844
    caps = None
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   845
    def capable(x):
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   846
        raise error.ProgrammingError('should not be called')
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   847
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   848
    args = {}
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   849
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   850
    # 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
   851
    # 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
   852
    # X-HgProto-* header advertising which serializing formats it supports.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   853
    # 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
   854
    # now.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   855
    advertisev2 = ui.configbool('experimental', 'httppeer.advertise-v2')
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   856
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   857
    if advertisev2:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   858
        args['headers'] = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   859
            r'X-HgProto-1': r'cbor',
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   860
        }
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
        args['headers'].update(
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   863
            encodevalueinheaders(' '.join(sorted(API_PEERS)),
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   864
                                 'X-HgUpgrade',
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   865
                                 # We don't know the header limit this early.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   866
                                 # So make it small.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   867
                                 1024))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   868
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   869
    req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps,
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   870
                                           capable, url, 'capabilities',
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   871
                                           args)
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   872
    resp = sendrequest(ui, opener, req)
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   873
37832
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   874
    # 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
   875
    # ?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
   876
    # 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
   877
    # 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
   878
    # the new URL.
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   879
    #
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   880
    # 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
   881
    # 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
   882
    # 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
   883
    # 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
   884
    # 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
   885
    # 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
   886
    try:
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   887
        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
   888
                                                   compressible=False,
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   889
                                                   allowcbor=advertisev2)
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   890
    except RedirectedRepoError as e:
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   891
        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
   892
                                               capable, e.respurl,
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   893
                                               'capabilities', args)
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   894
        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
   895
        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
   896
                                                   compressible=False,
6169d95dce3b httppeer: detect redirect to URL without query string (issue5860)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37810
diff changeset
   897
                                                   allowcbor=advertisev2)
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   898
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   899
    try:
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   900
        rawdata = resp.read()
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   901
    finally:
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   902
        resp.close()
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   903
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   904
    if not ct.startswith('application/mercurial-'):
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   905
        raise error.ProgrammingError('unexpected content-type: %s' % ct)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   906
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   907
    if advertisev2:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   908
        if ct == 'application/mercurial-cbor':
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   909
            try:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   910
                info = cbor.loads(rawdata)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   911
            except cbor.CBORDecodeError:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   912
                raise error.Abort(_('error decoding CBOR from remote server'),
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   913
                                  hint=_('try again and consider contacting '
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   914
                                         'the server operator'))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   915
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   916
        # We got a legacy response. That's fine.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   917
        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
   918
            info = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   919
                'v1capabilities': set(rawdata.split())
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
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   922
        else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   923
            raise error.RepoError(
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   924
                _('unexpected response type from server: %s') % ct)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   925
    else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   926
        info = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   927
            'v1capabilities': set(rawdata.split())
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   928
        }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   929
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   930
    return respurl, info
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
   931
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
   932
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
   933
    """Construct an appropriate HTTP peer instance.
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
   934
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
   935
    ``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
   936
    connections, perform HTTP requests.
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
   937
37547
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
   938
    ``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
   939
    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
   940
    """
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   941
    u = util.url(path)
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   942
    if u.query or u.fragment:
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   943
        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
   944
                          (u.query or u.fragment))
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   945
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   946
    # 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
   947
    url, authinfo = u.authinfo()
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   948
    ui.debug('using %s\n' % url)
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   949
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
   950
    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
   951
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   952
    respurl, info = performhandshake(ui, url, opener, requestbuilder)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   953
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   954
    # 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
   955
    # 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
   956
    #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   957
    # 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
   958
    # 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
   959
    # 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
   960
    # capabilities, we could filter out services not meeting the
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   961
    # requirements. Possibly by consulting the interfaces defined by the
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   962
    # peer type.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   963
    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
   964
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   965
    preferredchoices = sorted(apipeerchoices,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   966
                              key=lambda x: API_PEERS[x]['priority'],
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   967
                              reverse=True)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   968
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   969
    for service in preferredchoices:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   970
        apipath = '%s/%s' % (info['apibase'].rstrip('/'), service)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   971
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   972
        return API_PEERS[service]['init'](ui, respurl, apipath, opener,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   973
                                          requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   974
                                          info['apis'][service])
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   975
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   976
    # 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
   977
    return httppeer(ui, path, respurl, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
   978
                    info['v1capabilities'])
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   979
37717
0664be4f0c1f hg: pass command intents to repo/peer creation (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37669
diff changeset
   980
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
   981
    if create:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25954
diff changeset
   982
        raise error.Abort(_('cannot create new http repository'))
7211
25c0dee16ee0 Autodetect static-http
Matt Mackall <mpm@selenic.com>
parents: 7207
diff changeset
   983
    try:
36959
43815d87c6aa httppeer: alias url as urlmod
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36835
diff changeset
   984
        if path.startswith('https:') and not urlmod.has_https:
36220
874209855f5c httppeer: remove httpspeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36219
diff changeset
   985
            raise error.Abort(_('Python support for SSL and HTTPS '
874209855f5c httppeer: remove httpspeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36219
diff changeset
   986
                                '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
   987
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
   988
        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
   989
7211
25c0dee16ee0 Autodetect static-http
Matt Mackall <mpm@selenic.com>
parents: 7207
diff changeset
   990
        return inst
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25500
diff changeset
   991
    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
   992
        try:
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
   993
            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
   994
            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
   995
            return r
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
   996
        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
   997
            raise httpexception # use the original http RepoError instead