##// END OF EJS Templates
fix: auth. Disable httpostargs until auth problems are resolved
super-admin -
r1284:e0dbbf3d default
parent child Browse files
Show More
@@ -1,258 +1,258 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2023 RhodeCode GmbH
3 3 #
4 4 # This program is free software; you can redistribute it and/or modify
5 5 # it under the terms of the GNU General Public License as published by
6 6 # the Free Software Foundation; either version 3 of the License, or
7 7 # (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software Foundation,
16 16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 17
18 18 import os
19 19 import logging
20 20 import itertools
21 21
22 22 import mercurial
23 23 import mercurial.error
24 24 import mercurial.wireprotoserver
25 25 import mercurial.hgweb.common
26 26 import mercurial.hgweb.hgweb_mod
27 27 import webob.exc
28 28
29 29 from vcsserver import pygrack, exceptions, settings, git_lfs
30 30 from vcsserver.lib.str_utils import ascii_bytes, safe_bytes
31 31
32 32 log = logging.getLogger(__name__)
33 33
34 34
35 35 # propagated from mercurial documentation
36 36 HG_UI_SECTIONS = [
37 37 'alias', 'auth', 'decode/encode', 'defaults', 'diff', 'email', 'extensions',
38 38 'format', 'merge-patterns', 'merge-tools', 'hooks', 'http_proxy', 'smtp',
39 39 'patch', 'paths', 'profiling', 'server', 'trusted', 'ui', 'web',
40 40 ]
41 41
42 42
43 43 class HgWeb(mercurial.hgweb.hgweb_mod.hgweb):
44 44 """Extension of hgweb that simplifies some functions."""
45 45
46 46 def _get_view(self, repo):
47 47 """Views are not supported."""
48 48 return repo
49 49
50 50 def loadsubweb(self):
51 51 """The result is only used in the templater method which is not used."""
52 52 return None
53 53
54 54 def run(self):
55 55 """Unused function so raise an exception if accidentally called."""
56 56 raise NotImplementedError
57 57
58 58 def templater(self, req):
59 59 """Function used in an unreachable code path.
60 60
61 61 This code is unreachable because we guarantee that the HTTP request,
62 62 corresponds to a Mercurial command. See the is_hg method. So, we are
63 63 never going to get a user-visible url.
64 64 """
65 65 raise NotImplementedError
66 66
67 67 def archivelist(self, nodeid):
68 68 """Unused function so raise an exception if accidentally called."""
69 69 raise NotImplementedError
70 70
71 71 def __call__(self, environ, start_response):
72 72 """Run the WSGI application.
73 73
74 74 This may be called by multiple threads.
75 75 """
76 76 from mercurial.hgweb import request as requestmod
77 77 req = requestmod.parserequestfromenv(environ)
78 78 res = requestmod.wsgiresponse(req, start_response)
79 79 gen = self.run_wsgi(req, res)
80 80
81 81 first_chunk = None
82 82
83 83 try:
84 84 data = next(gen)
85 85
86 86 def first_chunk():
87 87 yield data
88 88 except StopIteration:
89 89 pass
90 90
91 91 if first_chunk:
92 92 return itertools.chain(first_chunk(), gen)
93 93 return gen
94 94
95 95 def _runwsgi(self, req, res, repo):
96 96
97 97 cmd = req.qsparams.get(b'cmd', '')
98 98 if not mercurial.wireprotoserver.iscmd(cmd):
99 99 # NOTE(marcink): for unsupported commands, we return bad request
100 100 # internally from HG
101 101 log.warning('cmd: `%s` is not supported by the mercurial wireprotocol v1', cmd)
102 102 from mercurial.hgweb.common import statusmessage
103 103 res.status = statusmessage(mercurial.hgweb.common.HTTP_BAD_REQUEST)
104 104 res.setbodybytes(b'')
105 105 return res.sendresponse()
106 106
107 107 return super()._runwsgi(req, res, repo)
108 108
109 109
110 110 def sanitize_hg_ui(baseui):
111 111 # NOTE(marcink): since python3 hgsubversion is deprecated.
112 112 # From old installations we might still have this set enabled
113 113 # we explicitly remove this now here to make sure it wont propagate further
114 114
115 115 if baseui.config(b'extensions', b'hgsubversion') is not None:
116 116 for cfg in (baseui._ocfg, baseui._tcfg, baseui._ucfg):
117 117 if b'extensions' in cfg:
118 118 if b'hgsubversion' in cfg[b'extensions']:
119 119 del cfg[b'extensions'][b'hgsubversion']
120 120
121 121
122 122 def make_hg_ui_from_config(repo_config):
123 123 baseui = mercurial.ui.ui()
124 124
125 125 # clean the baseui object
126 126 baseui._ocfg = mercurial.config.config()
127 127 baseui._ucfg = mercurial.config.config()
128 128 baseui._tcfg = mercurial.config.config()
129 129
130 130 for section, option, value in repo_config:
131 131 baseui.setconfig(
132 132 ascii_bytes(section, allow_bytes=True),
133 133 ascii_bytes(option, allow_bytes=True),
134 134 ascii_bytes(value, allow_bytes=True))
135 135
136 136 # make our hgweb quiet so it doesn't print output
137 137 baseui.setconfig(b'ui', b'quiet', b'true')
138 138
139 139 # use POST requests with args instead of GET with headers - fixes issues with big repos with lots of branches
140 baseui.setconfig(b'experimental', b'httppostargs', b'true')
140 baseui.setconfig(b'experimental', b'httppostargs', b'false')
141 141
142 142 return baseui
143 143
144 144
145 145 def update_hg_ui_from_hgrc(baseui, repo_path):
146 146 path = os.path.join(repo_path, '.hg', 'hgrc')
147 147
148 148 if not os.path.isfile(path):
149 149 log.debug('hgrc file is not present at %s, skipping...', path)
150 150 return
151 151 log.debug('reading hgrc from %s', path)
152 152 cfg = mercurial.config.config()
153 153 cfg.read(ascii_bytes(path))
154 154 for section in HG_UI_SECTIONS:
155 155 for k, v in cfg.items(section):
156 156 log.debug('settings ui from file: [%s] %s=%s', section, k, v)
157 157 baseui.setconfig(
158 158 ascii_bytes(section, allow_bytes=True),
159 159 ascii_bytes(k, allow_bytes=True),
160 160 ascii_bytes(v, allow_bytes=True))
161 161
162 162
163 163 def create_hg_wsgi_app(repo_path, repo_name, config):
164 164 """
165 165 Prepares a WSGI application to handle Mercurial requests.
166 166
167 167 :param config: is a list of 3-item tuples representing a ConfigObject
168 168 (it is the serialized version of the config object).
169 169 """
170 170 log.debug("Creating Mercurial WSGI application")
171 171
172 172 baseui = make_hg_ui_from_config(config)
173 173 update_hg_ui_from_hgrc(baseui, repo_path)
174 174 sanitize_hg_ui(baseui)
175 175
176 176 try:
177 177 return HgWeb(safe_bytes(repo_path), name=safe_bytes(repo_name), baseui=baseui)
178 178 except mercurial.error.RequirementError as e:
179 179 raise exceptions.RequirementException(e)(e)
180 180
181 181
182 182 class GitHandler:
183 183 """
184 184 Handler for Git operations like push/pull etc
185 185 """
186 186 def __init__(self, repo_location, repo_name, git_path, update_server_info,
187 187 extras):
188 188 if not os.path.isdir(repo_location):
189 189 raise OSError(repo_location)
190 190 self.content_path = repo_location
191 191 self.repo_name = repo_name
192 192 self.repo_location = repo_location
193 193 self.extras = extras
194 194 self.git_path = git_path
195 195 self.update_server_info = update_server_info
196 196
197 197 def __call__(self, environ, start_response):
198 198 app = webob.exc.HTTPNotFound()
199 199 candidate_paths = (
200 200 self.content_path, os.path.join(self.content_path, '.git'))
201 201
202 202 for content_path in candidate_paths:
203 203 try:
204 204 app = pygrack.GitRepository(
205 205 self.repo_name, content_path, self.git_path,
206 206 self.update_server_info, self.extras)
207 207 break
208 208 except OSError:
209 209 continue
210 210
211 211 return app(environ, start_response)
212 212
213 213
214 214 def create_git_wsgi_app(repo_path, repo_name, config):
215 215 """
216 216 Creates a WSGI application to handle Git requests.
217 217
218 218 :param config: is a dictionary holding the extras.
219 219 """
220 220 git_path = settings.GIT_EXECUTABLE()
221 221 update_server_info = config.pop('git_update_server_info')
222 222 app = GitHandler(
223 223 repo_path, repo_name, git_path, update_server_info, config)
224 224
225 225 return app
226 226
227 227
228 228 class GitLFSHandler:
229 229 """
230 230 Handler for Git LFS operations
231 231 """
232 232
233 233 def __init__(self, repo_location, repo_name, git_path, update_server_info,
234 234 extras):
235 235 if not os.path.isdir(repo_location):
236 236 raise OSError(repo_location)
237 237 self.content_path = repo_location
238 238 self.repo_name = repo_name
239 239 self.repo_location = repo_location
240 240 self.extras = extras
241 241 self.git_path = git_path
242 242 self.update_server_info = update_server_info
243 243
244 244 def get_app(self, git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme):
245 245 app = git_lfs.create_app(git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme)
246 246 return app
247 247
248 248
249 249 def create_git_lfs_wsgi_app(repo_path, repo_name, config):
250 250 git_path = settings.GIT_EXECUTABLE()
251 251 update_server_info = config.pop('git_update_server_info')
252 252 git_lfs_enabled = config.pop('git_lfs_enabled')
253 253 git_lfs_store_path = config.pop('git_lfs_store_path')
254 254 git_lfs_http_scheme = config.pop('git_lfs_http_scheme', 'http')
255 255 app = GitLFSHandler(
256 256 repo_path, repo_name, git_path, update_server_info, config)
257 257
258 258 return app.get_app(git_lfs_enabled, git_lfs_store_path, git_lfs_http_scheme)
General Comments 0
You need to be logged in to leave comments. Login now