##// END OF EJS Templates
hg: support new clonebundles_manifest write protocol command...
Mads Kiilerich -
r8789:0245e0eb stable
parent child Browse files
Show More
@@ -1,149 +1,150 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 kallithea.config.middleware.simplehg
16 16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17 17
18 18 SimpleHg middleware for handling Mercurial protocol requests (push/clone etc.).
19 19 It's implemented with basic auth function
20 20
21 21 This file was forked by the Kallithea project in July 2014.
22 22 Original author and date, and relevant copyright and licensing information is below:
23 23 :created_on: Apr 28, 2010
24 24 :author: marcink
25 25 :copyright: (c) 2013 RhodeCode GmbH, and others.
26 26 :license: GPLv3, see LICENSE.md for more details.
27 27
28 28 """
29 29
30 30
31 31 import logging
32 32 import os
33 33 import urllib.parse
34 34
35 35 import mercurial.hgweb
36 36
37 37 from kallithea.controllers import base
38 38 from kallithea.lib.utils import make_ui
39 39 from kallithea.lib.utils2 import safe_bytes
40 40
41 41
42 42 log = logging.getLogger(__name__)
43 43
44 44
45 45 def get_header_hgarg(environ):
46 46 """Decode the special Mercurial encoding of big requests over multiple headers.
47 47 >>> get_header_hgarg({})
48 48 ''
49 49 >>> get_header_hgarg({'HTTP_X_HGARG_0': ' ', 'HTTP_X_HGARG_1': 'a','HTTP_X_HGARG_2': '','HTTP_X_HGARG_3': 'b+c %20'})
50 50 'ab+c %20'
51 51 """
52 52 chunks = []
53 53 i = 1
54 54 while True:
55 55 v = environ.get('HTTP_X_HGARG_%d' % i)
56 56 if v is None:
57 57 break
58 58 chunks.append(v)
59 59 i += 1
60 60 return ''.join(chunks)
61 61
62 62
63 63 cmd_mapping = {
64 64 # 'batch' is not in this list - it is handled explicitly
65 65 'between': 'pull',
66 66 'branches': 'pull',
67 67 'branchmap': 'pull',
68 68 'capabilities': 'pull',
69 69 'changegroup': 'pull',
70 70 'changegroupsubset': 'pull',
71 71 'changesetdata': 'pull',
72 72 'clonebundles': 'pull',
73 'clonebundles_manifest': 'pull',
73 74 'debugwireargs': 'pull',
74 75 'filedata': 'pull',
75 76 'getbundle': 'pull',
76 77 'getlfile': 'pull',
77 78 'heads': 'pull',
78 79 'hello': 'pull',
79 80 'known': 'pull',
80 81 'lheads': 'pull',
81 82 'listkeys': 'pull',
82 83 'lookup': 'pull',
83 84 'manifestdata': 'pull',
84 85 'narrow_widen': 'pull',
85 86 'protocaps': 'pull',
86 87 'statlfile': 'pull',
87 88 'stream_out': 'pull',
88 89 'pushkey': 'push',
89 90 'putlfile': 'push',
90 91 'unbundle': 'push',
91 92 }
92 93
93 94
94 95 class SimpleHg(base.BaseVCSController):
95 96
96 97 scm_alias = 'hg'
97 98
98 99 @classmethod
99 100 def parse_request(cls, environ):
100 101 http_accept = environ.get('HTTP_ACCEPT', '')
101 102 if not http_accept.startswith('application/mercurial'):
102 103 return None
103 104 path_info = base.get_path_info(environ)
104 105 if not path_info.startswith('/'): # it must!
105 106 return None
106 107
107 108 class parsed_request(object):
108 109 repo_name = path_info[1:].rstrip('/')
109 110
110 111 query_string = environ['QUERY_STRING']
111 112
112 113 action = None
113 114 for qry in query_string.split('&'):
114 115 parts = qry.split('=', 1)
115 116 if len(parts) == 2 and parts[0] == 'cmd':
116 117 cmd = parts[1]
117 118 if cmd == 'batch':
118 119 hgarg = get_header_hgarg(environ)
119 120 if not hgarg.startswith('cmds='):
120 121 action = 'push' # paranoid and safe
121 122 break
122 123 action = 'pull'
123 124 for cmd_arg in hgarg[5:].split(';'):
124 125 cmd, _args = urllib.parse.unquote_plus(cmd_arg).split(' ', 1)
125 126 op = cmd_mapping.get(cmd, 'push')
126 127 if op != 'pull':
127 128 assert op == 'push'
128 129 action = 'push'
129 130 break
130 131 else:
131 132 action = cmd_mapping.get(cmd, 'push')
132 133 break # only process one cmd
133 134
134 135 return parsed_request
135 136
136 137 def _make_app(self, parsed_request):
137 138 """
138 139 Make an hgweb wsgi application.
139 140 """
140 141 repo_name = parsed_request.repo_name
141 142 repo_path = os.path.join(self.basepath, repo_name)
142 143 baseui = make_ui(repo_path=repo_path)
143 144 hgweb_app = mercurial.hgweb.hgweb(safe_bytes(repo_path), name=safe_bytes(repo_name), baseui=baseui)
144 145
145 146 def wrapper_app(environ, start_response):
146 147 environ['REPO_NAME'] = repo_name # used by mercurial.hgweb.hgweb
147 148 return hgweb_app(environ, start_response)
148 149
149 150 return wrapper_app
General Comments 0
You need to be logged in to leave comments. Login now