148 # 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 |
149 # hook if remotefilelog becomes a first-party extension. |
149 # hook if remotefilelog becomes a first-party extension. |
150 def iscmd(cmd): |
150 def iscmd(cmd): |
151 return cmd in wireproto.commands |
151 return cmd in wireproto.commands |
152 |
152 |
153 def parsehttprequest(rctx, wsgireq, req, checkperm): |
153 def handlewsgirequest(rctx, wsgireq, req, checkperm): |
154 """Parse the HTTP request for a wire protocol request. |
154 """Possibly process a wire protocol request. |
155 |
155 |
156 If the current request appears to be a wire protocol request, this |
156 If the current request is a wire protocol request, the request is |
157 function returns a dict with details about that request, including |
157 processed by this function. |
158 an ``abstractprotocolserver`` instance suitable for handling the |
|
159 request. Otherwise, ``None`` is returned. |
|
160 |
158 |
161 ``wsgireq`` is a ``wsgirequest`` instance. |
159 ``wsgireq`` is a ``wsgirequest`` instance. |
162 ``req`` is a ``parsedrequest`` instance. |
160 ``req`` is a ``parsedrequest`` instance. |
|
161 |
|
162 Returns a 2-tuple of (bool, response) where the 1st element indicates |
|
163 whether the request was handled and the 2nd element is a return |
|
164 value for a WSGI application (often a generator of bytes). |
163 """ |
165 """ |
|
166 # Avoid cycle involving hg module. |
|
167 from .hgweb import common as hgwebcommon |
|
168 |
164 repo = rctx.repo |
169 repo = rctx.repo |
165 |
170 |
166 # HTTP version 1 wire protocol requests are denoted by a "cmd" query |
171 # HTTP version 1 wire protocol requests are denoted by a "cmd" query |
167 # string parameter. If it isn't present, this isn't a wire protocol |
172 # string parameter. If it isn't present, this isn't a wire protocol |
168 # request. |
173 # request. |
169 if 'cmd' not in req.querystringdict: |
174 if 'cmd' not in req.querystringdict: |
170 return None |
175 return False, None |
171 |
176 |
172 cmd = req.querystringdict['cmd'][0] |
177 cmd = req.querystringdict['cmd'][0] |
173 |
178 |
174 # The "cmd" request parameter is used by both the wire protocol and hgweb. |
179 # The "cmd" request parameter is used by both the wire protocol and hgweb. |
175 # While not all wire protocol commands are available for all transports, |
180 # While not all wire protocol commands are available for all transports, |
177 # route it to a protocol handler. This is better than routing possible |
182 # route it to a protocol handler. This is better than routing possible |
178 # wire protocol requests to hgweb because it prevents hgweb from using |
183 # wire protocol requests to hgweb because it prevents hgweb from using |
179 # known wire protocol commands and it is less confusing for machine |
184 # known wire protocol commands and it is less confusing for machine |
180 # clients. |
185 # clients. |
181 if not iscmd(cmd): |
186 if not iscmd(cmd): |
182 return None |
187 return False, None |
|
188 |
|
189 # The "cmd" query string argument is only valid on the root path of the |
|
190 # repo. e.g. ``/?cmd=foo``, ``/repo?cmd=foo``. URL paths within the repo |
|
191 # like ``/blah?cmd=foo`` are not allowed. So don't recognize the request |
|
192 # in this case. We send an HTTP 404 for backwards compatibility reasons. |
|
193 if req.dispatchpath: |
|
194 res = _handlehttperror( |
|
195 hgwebcommon.ErrorResponse(hgwebcommon.HTTP_NOT_FOUND), wsgireq, |
|
196 cmd) |
|
197 |
|
198 return True, res |
183 |
199 |
184 proto = httpv1protocolhandler(wsgireq, repo.ui, |
200 proto = httpv1protocolhandler(wsgireq, repo.ui, |
185 lambda perm: checkperm(rctx, wsgireq, perm)) |
201 lambda perm: checkperm(rctx, wsgireq, perm)) |
186 |
202 |
187 return { |
203 # The permissions checker should be the only thing that can raise an |
188 'cmd': cmd, |
204 # ErrorResponse. It is kind of a layer violation to catch an hgweb |
189 'proto': proto, |
205 # exception here. So consider refactoring into a exception type that |
190 'dispatch': lambda: _callhttp(repo, wsgireq, proto, cmd), |
206 # is associated with the wire protocol. |
191 'handleerror': lambda ex: _handlehttperror(ex, wsgireq, cmd), |
207 try: |
192 } |
208 res = _callhttp(repo, wsgireq, proto, cmd) |
|
209 except hgwebcommon.ErrorResponse as e: |
|
210 res = _handlehttperror(e, wsgireq, cmd) |
|
211 |
|
212 return True, res |
193 |
213 |
194 def _httpresponsetype(ui, wsgireq, prefer_uncompressed): |
214 def _httpresponsetype(ui, wsgireq, prefer_uncompressed): |
195 """Determine the appropriate response type and compression settings. |
215 """Determine the appropriate response type and compression settings. |
196 |
216 |
197 Returns a tuple of (mediatype, compengine, engineopts). |
217 Returns a tuple of (mediatype, compengine, engineopts). |