# HG changeset patch # User Gregory Szorc # Date 1482615962 25200 # Node ID 3f5f0c98cd18c40a9816e463dc828288414d1878 # Parent 76104a4899ad082744cf5413785507c7637029c9 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. diff -r 76104a4899ad -r 3f5f0c98cd18 mercurial/hgweb/protocol.py --- 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']) diff -r 76104a4899ad -r 3f5f0c98cd18 mercurial/httppeer.py --- 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-`` where ```` 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())