comparison mercurial/httppeer.py @ 30763:a520aefb96f1

httppeer: advertise and support application/mercurial-0.2 Now that servers expose a capability indicating they support application/mercurial-0.2 and compression, clients can key off this to say they support responses that are compressed with various compression formats. After this commit, the HTTP wire protocol client now sends an "X-HgProto-<N>" request header indicating its support for "application/mercurial-0.2" media type and various compression formats. This commit also implements support for handling "application/mercurial-0.2" responses. It simply reads the header compression engine identifier then routes the remainder of the response to the appropriate decompressor. There were some test changes, but only to logging. That points to an obvious gap in our test coverage. This will be addressed in a subsequent commit once server support is in place (it is hard to test without server support).
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 24 Dec 2016 15:22:18 -0700
parents 3f5f0c98cd18
children 48dea083f66d
comparison
equal deleted inserted replaced
30762:35b516f800e0 30763:a520aefb96f1
9 from __future__ import absolute_import 9 from __future__ import absolute_import
10 10
11 import errno 11 import errno
12 import os 12 import os
13 import socket 13 import socket
14 import struct
14 import tempfile 15 import tempfile
15 16
16 from .i18n import _ 17 from .i18n import _
17 from .node import nullid 18 from .node import nullid
18 from . import ( 19 from . import (
172 headers['Expect'] = '100-Continue' 173 headers['Expect'] = '100-Continue'
173 headers['X-HgHttp2'] = '1' 174 headers['X-HgHttp2'] = '1'
174 if data is not None and 'Content-Type' not in headers: 175 if data is not None and 'Content-Type' not in headers:
175 headers['Content-Type'] = 'application/mercurial-0.1' 176 headers['Content-Type'] = 'application/mercurial-0.1'
176 177
178 # Tell the server we accept application/mercurial-0.2 and multiple
179 # compression formats if the server is capable of emitting those
180 # payloads.
181 protoparams = []
182
183 mediatypes = set()
184 if self.caps is not None:
185 mt = self.capable('httpmediatype')
186 if mt:
187 protoparams.append('0.1')
188 mediatypes = set(mt.split(','))
189
190 if '0.2tx' in mediatypes:
191 protoparams.append('0.2')
192
193 if '0.2tx' in mediatypes and self.capable('compression'):
194 # We /could/ compare supported compression formats and prune
195 # non-mutually supported or error if nothing is mutually supported.
196 # For now, send the full list to the server and have it error.
197 comps = [e.wireprotosupport().name for e in
198 util.compengines.supportedwireengines(util.CLIENTROLE)]
199 protoparams.append('comp=%s' % ','.join(comps))
200
201 if protoparams:
202 protoheaders = encodevalueinheaders(' '.join(protoparams),
203 'X-HgProto',
204 headersize or 1024)
205 for header, value in protoheaders:
206 headers[header] = value
207 varyheaders.append(header)
208
177 headers['Vary'] = ','.join(varyheaders) 209 headers['Vary'] = ','.join(varyheaders)
178 req = self.requestbuilder(cu, data, headers) 210 req = self.requestbuilder(cu, data, headers)
179 211
180 if data is not None: 212 if data is not None:
181 self.ui.debug("sending %s bytes\n" % size) 213 self.ui.debug("sending %s bytes\n" % size)
222 version = proto.split('-', 1)[1] 254 version = proto.split('-', 1)[1]
223 version_info = tuple([int(n) for n in version.split('.')]) 255 version_info = tuple([int(n) for n in version.split('.')])
224 except ValueError: 256 except ValueError:
225 raise error.RepoError(_("'%s' sent a broken Content-Type " 257 raise error.RepoError(_("'%s' sent a broken Content-Type "
226 "header (%s)") % (safeurl, proto)) 258 "header (%s)") % (safeurl, proto))
227 if version_info > (0, 1): 259
260 if version_info == (0, 1):
261 if _compressible:
262 return decompressresponse(resp, util.compengines['zlib'])
263 return resp
264 elif version_info == (0, 2):
265 # application/mercurial-0.2 always identifies the compression
266 # engine in the payload header.
267 elen = struct.unpack('B', resp.read(1))[0]
268 ename = resp.read(elen)
269 engine = util.compengines.forwiretype(ename)
270 return decompressresponse(resp, engine)
271 else:
228 raise error.RepoError(_("'%s' uses newer protocol %s") % 272 raise error.RepoError(_("'%s' uses newer protocol %s") %
229 (safeurl, version)) 273 (safeurl, version))
230 274
231 if _compressible: 275 if _compressible:
232 return decompressresponse(resp, util.compengines['zlib']) 276 return decompressresponse(resp, util.compengines['zlib'])