##// END OF EJS Templates
wireprotoserver: access headers through parsed request...
Gregory Szorc -
r36862:14f70c44 default
parent child Browse files
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(wsgireq, headerprefix):
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 = wsgireq.env.get(r'HTTP_%s_%d' % (prefix, i))
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._wsgireq.env.get(r'HTTP_X_HGARGS_POST', 0))
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._wsgireq, r'X-HgArg')
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._wsgireq.env[r'HTTP_CONTENT_LENGTH'])
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._wsgireq.env.get(r'HTTP_X_HGARGS_POST', 0))
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, wsgireq, prefer_uncompressed):
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(wsgireq, r'X-HgProto').split(' ')
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, wsgireq, rsp.prefer_uncompressed)
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