Changeset - 0245e0ebddd0
[Not reviewed]
stable
0 1 0
Mads Kiilerich (mads) - 20 months ago 2024-07-23 16:23:16
mads@kiilerich.com
hg: support new clonebundles_manifest write protocol command

A new wire protocol command was introduced with Mercurial 6.5 -
https://repo.mercurial-scm.org/hg/rev/4238e6b22fc4 .

When a client (after negotiation with the server) decided to use this new
command, Kallithea would fail safely and require write permissions.

Fixed by adding it to the list of known read-only commands.
1 file changed with 1 insertions and 0 deletions:
0 comments (0 inline, 0 general)
kallithea/config/middleware/simplehg.py
Show inline comments
 
@@ -25,96 +25,97 @@ Original author and date, and relevant c
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 

	
 
"""
 

	
 

	
 
import logging
 
import os
 
import urllib.parse
 

	
 
import mercurial.hgweb
 

	
 
from kallithea.controllers import base
 
from kallithea.lib.utils import make_ui
 
from kallithea.lib.utils2 import safe_bytes
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def get_header_hgarg(environ):
 
    """Decode the special Mercurial encoding of big requests over multiple headers.
 
    >>> get_header_hgarg({})
 
    ''
 
    >>> get_header_hgarg({'HTTP_X_HGARG_0': ' ', 'HTTP_X_HGARG_1': 'a','HTTP_X_HGARG_2': '','HTTP_X_HGARG_3': 'b+c %20'})
 
    'ab+c %20'
 
    """
 
    chunks = []
 
    i = 1
 
    while True:
 
        v = environ.get('HTTP_X_HGARG_%d' % i)
 
        if v is None:
 
            break
 
        chunks.append(v)
 
        i += 1
 
    return ''.join(chunks)
 

	
 

	
 
cmd_mapping = {
 
    # 'batch' is not in this list - it is handled explicitly
 
    'between': 'pull',
 
    'branches': 'pull',
 
    'branchmap': 'pull',
 
    'capabilities': 'pull',
 
    'changegroup': 'pull',
 
    'changegroupsubset': 'pull',
 
    'changesetdata': 'pull',
 
    'clonebundles': 'pull',
 
    'clonebundles_manifest': 'pull',
 
    'debugwireargs': 'pull',
 
    'filedata': 'pull',
 
    'getbundle': 'pull',
 
    'getlfile': 'pull',
 
    'heads': 'pull',
 
    'hello': 'pull',
 
    'known': 'pull',
 
    'lheads': 'pull',
 
    'listkeys': 'pull',
 
    'lookup': 'pull',
 
    'manifestdata': 'pull',
 
    'narrow_widen': 'pull',
 
    'protocaps': 'pull',
 
    'statlfile': 'pull',
 
    'stream_out': 'pull',
 
    'pushkey': 'push',
 
    'putlfile': 'push',
 
    'unbundle': 'push',
 
    }
 

	
 

	
 
class SimpleHg(base.BaseVCSController):
 

	
 
    scm_alias = 'hg'
 

	
 
    @classmethod
 
    def parse_request(cls, environ):
 
        http_accept = environ.get('HTTP_ACCEPT', '')
 
        if not http_accept.startswith('application/mercurial'):
 
            return None
 
        path_info = base.get_path_info(environ)
 
        if not path_info.startswith('/'): # it must!
 
            return None
 

	
 
        class parsed_request(object):
 
            repo_name = path_info[1:].rstrip('/')
 

	
 
            query_string = environ['QUERY_STRING']
 

	
 
            action = None
 
            for qry in query_string.split('&'):
 
                parts = qry.split('=', 1)
 
                if len(parts) == 2 and parts[0] == 'cmd':
 
                    cmd = parts[1]
 
                    if cmd == 'batch':
 
                        hgarg = get_header_hgarg(environ)
 
                        if not hgarg.startswith('cmds='):
 
                            action = 'push' # paranoid and safe
0 comments (0 inline, 0 general)