Show More
@@ -36,16 +36,15 b" HGERRTYPE = 'application/hg-error'" | |||||
36 | SSHV1 = wireprototypes.SSHV1 |
|
36 | SSHV1 = wireprototypes.SSHV1 | |
37 | SSHV2 = wireprototypes.SSHV2 |
|
37 | SSHV2 = wireprototypes.SSHV2 | |
38 |
|
38 | |||
39 |
def decodevaluefromheaders( |
|
39 | def decodevaluefromheaders(req, headerprefix): | |
40 | """Decode a long value from multiple HTTP request headers. |
|
40 | """Decode a long value from multiple HTTP request headers. | |
41 |
|
41 | |||
42 | Returns the value as a bytes, not a str. |
|
42 | Returns the value as a bytes, not a str. | |
43 | """ |
|
43 | """ | |
44 | chunks = [] |
|
44 | chunks = [] | |
45 | i = 1 |
|
45 | i = 1 | |
46 | prefix = headerprefix.upper().replace(r'-', r'_') |
|
|||
47 | while True: |
|
46 | while True: | |
48 |
v = |
|
47 | v = req.headers.get(b'%s-%d' % (headerprefix, i)) | |
49 | if v is None: |
|
48 | if v is None: | |
50 | break |
|
49 | break | |
51 | chunks.append(pycompat.bytesurl(v)) |
|
50 | chunks.append(pycompat.bytesurl(v)) | |
@@ -54,8 +53,9 b' def decodevaluefromheaders(wsgireq, head' | |||||
54 | return ''.join(chunks) |
|
53 | return ''.join(chunks) | |
55 |
|
54 | |||
56 | class httpv1protocolhandler(wireprototypes.baseprotocolhandler): |
|
55 | class httpv1protocolhandler(wireprototypes.baseprotocolhandler): | |
57 | def __init__(self, wsgireq, ui, checkperm): |
|
56 | def __init__(self, wsgireq, req, ui, checkperm): | |
58 | self._wsgireq = wsgireq |
|
57 | self._wsgireq = wsgireq | |
|
58 | self._req = req | |||
59 | self._ui = ui |
|
59 | self._ui = ui | |
60 | self._checkperm = checkperm |
|
60 | self._checkperm = checkperm | |
61 |
|
61 | |||
@@ -80,24 +80,24 b' class httpv1protocolhandler(wireprototyp' | |||||
80 |
|
80 | |||
81 | def _args(self): |
|
81 | def _args(self): | |
82 | args = util.rapply(pycompat.bytesurl, self._wsgireq.form.copy()) |
|
82 | args = util.rapply(pycompat.bytesurl, self._wsgireq.form.copy()) | |
83 |
postlen = int(self._ |
|
83 | postlen = int(self._req.headers.get(b'X-HgArgs-Post', 0)) | |
84 | if postlen: |
|
84 | if postlen: | |
85 | args.update(urlreq.parseqs( |
|
85 | args.update(urlreq.parseqs( | |
86 | self._wsgireq.read(postlen), keep_blank_values=True)) |
|
86 | self._wsgireq.read(postlen), keep_blank_values=True)) | |
87 | return args |
|
87 | return args | |
88 |
|
88 | |||
89 |
argvalue = decodevaluefromheaders(self._ |
|
89 | argvalue = decodevaluefromheaders(self._req, b'X-HgArg') | |
90 | args.update(urlreq.parseqs(argvalue, keep_blank_values=True)) |
|
90 | args.update(urlreq.parseqs(argvalue, keep_blank_values=True)) | |
91 | return args |
|
91 | return args | |
92 |
|
92 | |||
93 | def forwardpayload(self, fp): |
|
93 | def forwardpayload(self, fp): | |
94 | if r'HTTP_CONTENT_LENGTH' in self._wsgireq.env: |
|
94 | if b'Content-Length' in self._req.headers: | |
95 |
length = int(self._ |
|
95 | length = int(self._req.headers[b'Content-Length']) | |
96 | else: |
|
96 | else: | |
97 | length = int(self._wsgireq.env[r'CONTENT_LENGTH']) |
|
97 | length = int(self._wsgireq.env[r'CONTENT_LENGTH']) | |
98 | # If httppostargs is used, we need to read Content-Length |
|
98 | # If httppostargs is used, we need to read Content-Length | |
99 | # minus the amount that was consumed by args. |
|
99 | # minus the amount that was consumed by args. | |
100 |
length -= int(self._ |
|
100 | length -= int(self._req.headers.get(b'X-HgArgs-Post', 0)) | |
101 | for s in util.filechunkiter(self._wsgireq, limit=length): |
|
101 | for s in util.filechunkiter(self._wsgireq, limit=length): | |
102 | fp.write(s) |
|
102 | fp.write(s) | |
103 |
|
103 | |||
@@ -193,11 +193,11 b' def handlewsgirequest(rctx, wsgireq, req' | |||||
193 | if req.dispatchpath: |
|
193 | if req.dispatchpath: | |
194 | res = _handlehttperror( |
|
194 | res = _handlehttperror( | |
195 | hgwebcommon.ErrorResponse(hgwebcommon.HTTP_NOT_FOUND), wsgireq, |
|
195 | hgwebcommon.ErrorResponse(hgwebcommon.HTTP_NOT_FOUND), wsgireq, | |
196 | cmd) |
|
196 | req, cmd) | |
197 |
|
197 | |||
198 | return True, res |
|
198 | return True, res | |
199 |
|
199 | |||
200 | proto = httpv1protocolhandler(wsgireq, repo.ui, |
|
200 | proto = httpv1protocolhandler(wsgireq, req, repo.ui, | |
201 | lambda perm: checkperm(rctx, wsgireq, perm)) |
|
201 | lambda perm: checkperm(rctx, wsgireq, perm)) | |
202 |
|
202 | |||
203 | # The permissions checker should be the only thing that can raise an |
|
203 | # The permissions checker should be the only thing that can raise an | |
@@ -205,20 +205,20 b' def handlewsgirequest(rctx, wsgireq, req' | |||||
205 | # exception here. So consider refactoring into a exception type that |
|
205 | # exception here. So consider refactoring into a exception type that | |
206 | # is associated with the wire protocol. |
|
206 | # is associated with the wire protocol. | |
207 | try: |
|
207 | try: | |
208 | res = _callhttp(repo, wsgireq, proto, cmd) |
|
208 | res = _callhttp(repo, wsgireq, req, proto, cmd) | |
209 | except hgwebcommon.ErrorResponse as e: |
|
209 | except hgwebcommon.ErrorResponse as e: | |
210 | res = _handlehttperror(e, wsgireq, cmd) |
|
210 | res = _handlehttperror(e, wsgireq, req, cmd) | |
211 |
|
211 | |||
212 | return True, res |
|
212 | return True, res | |
213 |
|
213 | |||
214 |
def _httpresponsetype(ui, |
|
214 | def _httpresponsetype(ui, req, prefer_uncompressed): | |
215 | """Determine the appropriate response type and compression settings. |
|
215 | """Determine the appropriate response type and compression settings. | |
216 |
|
216 | |||
217 | Returns a tuple of (mediatype, compengine, engineopts). |
|
217 | Returns a tuple of (mediatype, compengine, engineopts). | |
218 | """ |
|
218 | """ | |
219 | # Determine the response media type and compression engine based |
|
219 | # Determine the response media type and compression engine based | |
220 | # on the request parameters. |
|
220 | # on the request parameters. | |
221 |
protocaps = decodevaluefromheaders( |
|
221 | protocaps = decodevaluefromheaders(req, 'X-HgProto').split(' ') | |
222 |
|
222 | |||
223 | if '0.2' in protocaps: |
|
223 | if '0.2' in protocaps: | |
224 | # All clients are expected to support uncompressed data. |
|
224 | # All clients are expected to support uncompressed data. | |
@@ -251,7 +251,7 b' def _httpresponsetype(ui, wsgireq, prefe' | |||||
251 | opts = {'level': ui.configint('server', 'zliblevel')} |
|
251 | opts = {'level': ui.configint('server', 'zliblevel')} | |
252 | return HGTYPE, util.compengines['zlib'], opts |
|
252 | return HGTYPE, util.compengines['zlib'], opts | |
253 |
|
253 | |||
254 | def _callhttp(repo, wsgireq, proto, cmd): |
|
254 | def _callhttp(repo, wsgireq, req, proto, cmd): | |
255 | def genversion2(gen, engine, engineopts): |
|
255 | def genversion2(gen, engine, engineopts): | |
256 | # application/mercurial-0.2 always sends a payload header |
|
256 | # application/mercurial-0.2 always sends a payload header | |
257 | # identifying the compression engine. |
|
257 | # identifying the compression engine. | |
@@ -289,7 +289,7 b' def _callhttp(repo, wsgireq, proto, cmd)' | |||||
289 | # This code for compression should not be streamres specific. It |
|
289 | # This code for compression should not be streamres specific. It | |
290 | # is here because we only compress streamres at the moment. |
|
290 | # is here because we only compress streamres at the moment. | |
291 | mediatype, engine, engineopts = _httpresponsetype( |
|
291 | mediatype, engine, engineopts = _httpresponsetype( | |
292 |
repo.ui, |
|
292 | repo.ui, req, rsp.prefer_uncompressed) | |
293 | gen = engine.compressstream(gen, engineopts) |
|
293 | gen = engine.compressstream(gen, engineopts) | |
294 |
|
294 | |||
295 | if mediatype == HGTYPE2: |
|
295 | if mediatype == HGTYPE2: | |
@@ -314,7 +314,7 b' def _callhttp(repo, wsgireq, proto, cmd)' | |||||
314 | return [] |
|
314 | return [] | |
315 | raise error.ProgrammingError('hgweb.protocol internal failure', rsp) |
|
315 | raise error.ProgrammingError('hgweb.protocol internal failure', rsp) | |
316 |
|
316 | |||
317 | def _handlehttperror(e, wsgireq, cmd): |
|
317 | def _handlehttperror(e, wsgireq, req, cmd): | |
318 | """Called when an ErrorResponse is raised during HTTP request processing.""" |
|
318 | """Called when an ErrorResponse is raised during HTTP request processing.""" | |
319 |
|
319 | |||
320 | # Clients using Python's httplib are stateful: the HTTP client |
|
320 | # Clients using Python's httplib are stateful: the HTTP client | |
@@ -327,8 +327,7 b' def _handlehttperror(e, wsgireq, cmd):' | |||||
327 |
|
327 | |||
328 | if (wsgireq.env[r'REQUEST_METHOD'] == r'POST' and |
|
328 | if (wsgireq.env[r'REQUEST_METHOD'] == r'POST' and | |
329 | # But not if Expect: 100-continue is being used. |
|
329 | # But not if Expect: 100-continue is being used. | |
330 | (wsgireq.env.get('HTTP_EXPECT', |
|
330 | (req.headers.get('Expect', '').lower() != '100-continue')): | |
331 | '').lower() != '100-continue')): |
|
|||
332 | wsgireq.drain() |
|
331 | wsgireq.drain() | |
333 | else: |
|
332 | else: | |
334 | wsgireq.headers.append((r'Connection', r'Close')) |
|
333 | wsgireq.headers.append((r'Connection', r'Close')) |
General Comments 0
You need to be logged in to leave comments.
Login now