137 for e in compengines) |
138 for e in compengines) |
138 caps.append('compression=%s' % comptypes) |
139 caps.append('compression=%s' % comptypes) |
139 |
140 |
140 return caps |
141 return caps |
141 |
142 |
|
143 def checkperm(self, perm): |
|
144 return self._checkperm(perm) |
|
145 |
142 # This method exists mostly so that extensions like remotefilelog can |
146 # This method exists mostly so that extensions like remotefilelog can |
143 # disable a kludgey legacy method only over http. As of early 2018, |
147 # disable a kludgey legacy method only over http. As of early 2018, |
144 # there are no other known users, so with any luck we can discard this |
148 # there are no other known users, so with any luck we can discard this |
145 # hook if remotefilelog becomes a first-party extension. |
149 # hook if remotefilelog becomes a first-party extension. |
146 def iscmd(cmd): |
150 def iscmd(cmd): |
147 return cmd in wireproto.commands |
151 return cmd in wireproto.commands |
148 |
152 |
149 def parsehttprequest(repo, req, query): |
153 def parsehttprequest(rctx, req, query, checkperm): |
150 """Parse the HTTP request for a wire protocol request. |
154 """Parse the HTTP request for a wire protocol request. |
151 |
155 |
152 If the current request appears to be a wire protocol request, this |
156 If the current request appears to be a wire protocol request, this |
153 function returns a dict with details about that request, including |
157 function returns a dict with details about that request, including |
154 an ``abstractprotocolserver`` instance suitable for handling the |
158 an ``abstractprotocolserver`` instance suitable for handling the |
155 request. Otherwise, ``None`` is returned. |
159 request. Otherwise, ``None`` is returned. |
156 |
160 |
157 ``req`` is a ``wsgirequest`` instance. |
161 ``req`` is a ``wsgirequest`` instance. |
158 """ |
162 """ |
|
163 repo = rctx.repo |
|
164 |
159 # HTTP version 1 wire protocol requests are denoted by a "cmd" query |
165 # HTTP version 1 wire protocol requests are denoted by a "cmd" query |
160 # string parameter. If it isn't present, this isn't a wire protocol |
166 # string parameter. If it isn't present, this isn't a wire protocol |
161 # request. |
167 # request. |
162 if 'cmd' not in req.form: |
168 if 'cmd' not in req.form: |
163 return None |
169 return None |
172 # known wire protocol commands and it is less confusing for machine |
178 # known wire protocol commands and it is less confusing for machine |
173 # clients. |
179 # clients. |
174 if not iscmd(cmd): |
180 if not iscmd(cmd): |
175 return None |
181 return None |
176 |
182 |
177 proto = httpv1protocolhandler(req, repo.ui) |
183 proto = httpv1protocolhandler(req, repo.ui, |
|
184 lambda perm: checkperm(rctx, req, perm)) |
178 |
185 |
179 return { |
186 return { |
180 'cmd': cmd, |
187 'cmd': cmd, |
181 'proto': proto, |
188 'proto': proto, |
182 'dispatch': lambda checkperm: _callhttp(repo, req, proto, cmd, |
189 'dispatch': lambda: _callhttp(repo, req, proto, cmd), |
183 checkperm), |
|
184 'handleerror': lambda ex: _handlehttperror(ex, req, cmd), |
190 'handleerror': lambda ex: _handlehttperror(ex, req, cmd), |
185 } |
191 } |
186 |
192 |
187 def _httpresponsetype(ui, req, prefer_uncompressed): |
193 def _httpresponsetype(ui, req, prefer_uncompressed): |
188 """Determine the appropriate response type and compression settings. |
194 """Determine the appropriate response type and compression settings. |
222 # setting a very high compression level could lead to flooding |
228 # setting a very high compression level could lead to flooding |
223 # the server's network or CPU. |
229 # the server's network or CPU. |
224 opts = {'level': ui.configint('server', 'zliblevel')} |
230 opts = {'level': ui.configint('server', 'zliblevel')} |
225 return HGTYPE, util.compengines['zlib'], opts |
231 return HGTYPE, util.compengines['zlib'], opts |
226 |
232 |
227 def _callhttp(repo, req, proto, cmd, checkperm): |
233 def _callhttp(repo, req, proto, cmd): |
228 def genversion2(gen, engine, engineopts): |
234 def genversion2(gen, engine, engineopts): |
229 # application/mercurial-0.2 always sends a payload header |
235 # application/mercurial-0.2 always sends a payload header |
230 # identifying the compression engine. |
236 # identifying the compression engine. |
231 name = engine.wireprotosupport().name |
237 name = engine.wireprotosupport().name |
232 assert 0 < len(name) < 256 |
238 assert 0 < len(name) < 256 |
240 req.respond(HTTP_OK, HGERRTYPE, |
246 req.respond(HTTP_OK, HGERRTYPE, |
241 body=_('requested wire protocol command is not available ' |
247 body=_('requested wire protocol command is not available ' |
242 'over HTTP')) |
248 'over HTTP')) |
243 return [] |
249 return [] |
244 |
250 |
245 checkperm(wireproto.commands[cmd].permission) |
251 proto.checkperm(wireproto.commands[cmd].permission) |
246 |
252 |
247 rsp = wireproto.dispatch(repo, proto, cmd) |
253 rsp = wireproto.dispatch(repo, proto, cmd) |
248 |
254 |
249 if isinstance(rsp, bytes): |
255 if isinstance(rsp, bytes): |
250 req.respond(HTTP_OK, HGTYPE, body=rsp) |
256 req.respond(HTTP_OK, HGTYPE, body=rsp) |
390 return 'remote:ssh:' + client |
396 return 'remote:ssh:' + client |
391 |
397 |
392 def addcapabilities(self, repo, caps): |
398 def addcapabilities(self, repo, caps): |
393 return caps |
399 return caps |
394 |
400 |
|
401 def checkperm(self, perm): |
|
402 pass |
|
403 |
395 class sshv2protocolhandler(sshv1protocolhandler): |
404 class sshv2protocolhandler(sshv1protocolhandler): |
396 """Protocol handler for version 2 of the SSH protocol.""" |
405 """Protocol handler for version 2 of the SSH protocol.""" |
397 |
406 |
398 @property |
407 @property |
399 def name(self): |
408 def name(self): |