httppeer: extract code for HTTP header spanning
A second consumer of HTTP header spanning will soon be introduced.
Factor out the code to do this so it can be reused.
--- a/mercurial/hgweb/protocol.py Tue Jan 10 11:20:32 2017 -0800
+++ b/mercurial/hgweb/protocol.py Sat Dec 24 14:46:02 2016 -0700
@@ -25,6 +25,20 @@
HGTYPE = 'application/mercurial-0.1'
HGERRTYPE = 'application/hg-error'
+def decodevaluefromheaders(req, headerprefix):
+ """Decode a long value from multiple HTTP request headers."""
+ chunks = []
+ i = 1
+ while True:
+ v = req.env.get('HTTP_%s_%d' % (
+ headerprefix.upper().replace('-', '_'), i))
+ if v is None:
+ break
+ chunks.append(v)
+ i += 1
+
+ return ''.join(chunks)
+
class webproto(wireproto.abstractserverproto):
def __init__(self, req, ui):
self.req = req
@@ -53,15 +67,9 @@
args.update(cgi.parse_qs(
self.req.read(postlen), keep_blank_values=True))
return args
- chunks = []
- i = 1
- while True:
- h = self.req.env.get('HTTP_X_HGARG_' + str(i))
- if h is None:
- break
- chunks += [h]
- i += 1
- args.update(cgi.parse_qs(''.join(chunks), keep_blank_values=True))
+
+ argvalue = decodevaluefromheaders(self.req, 'X-HgArg')
+ args.update(cgi.parse_qs(argvalue, keep_blank_values=True))
return args
def getfile(self, fp):
length = int(self.req.env['CONTENT_LENGTH'])
--- a/mercurial/httppeer.py Tue Jan 10 11:20:32 2017 -0800
+++ b/mercurial/httppeer.py Sat Dec 24 14:46:02 2016 -0700
@@ -53,6 +53,26 @@
reader.__class__ = readerproxy
return reader
+def encodevalueinheaders(value, header, limit):
+ """Encode a string value into multiple HTTP headers.
+
+ ``value`` will be encoded into 1 or more HTTP headers with the names
+ ``header-<N>`` where ``<N>`` is an integer starting at 1. Each header
+ name + value will be at most ``limit`` bytes long.
+
+ Returns an iterable of 2-tuples consisting of header names and values.
+ """
+ fmt = header + '-%s'
+ valuelen = limit - len(fmt % '000') - len(': \r\n')
+ result = []
+
+ n = 0
+ for i in xrange(0, len(value), valuelen):
+ n += 1
+ result.append((fmt % str(n), value[i:i + valuelen]))
+
+ return result
+
class httppeer(wireproto.wirepeer):
def __init__(self, ui, path):
self.path = path
@@ -135,13 +155,9 @@
if headersize > 0:
# The headers can typically carry more data than the URL.
encargs = urlreq.urlencode(sorted(args.items()))
- headerfmt = 'X-HgArg-%s'
- contentlen = headersize - len(headerfmt % '000' + ': \r\n')
- headernum = 0
- for i in xrange(0, len(encargs), contentlen):
- headernum += 1
- header = headerfmt % str(headernum)
- headers[header] = encargs[i:i + contentlen]
+ for header, value in encodevalueinheaders(encargs, 'X-HgArg',
+ headersize):
+ headers[header] = value
varyheaders.append(header)
else:
q += sorted(args.items())