comparison mercurial/hgweb/protocol.py @ 35750:a39a9df7ecca

wireproto: split streamres into legacy and modern case A couple of commands currently require transmission of uncompressed frames with the old MIME type. Split this case from streamres into a new streamres_legacy class. Streamline the remaining code accordingly. Add a new flag to streamres to request uncompressed streams. This is useful for sending data that is already compressed like a pre-built bundle. Expect clients to support uncompressed data. For older clients, zlib will still be used. Differential Revision: https://phab.mercurial-scm.org/D1862
author Joerg Sonnenberger <joerg@bec.de>
date Fri, 12 Jan 2018 10:59:58 +0100
parents 8cdb671dbd0b
children ff4bc0ab6740
comparison
equal deleted inserted replaced
35749:3a3b59bbe7ce 35750:a39a9df7ecca
100 return 'remote:%s:%s:%s' % ( 100 return 'remote:%s:%s:%s' % (
101 self.req.env.get('wsgi.url_scheme') or 'http', 101 self.req.env.get('wsgi.url_scheme') or 'http',
102 urlreq.quote(self.req.env.get('REMOTE_HOST', '')), 102 urlreq.quote(self.req.env.get('REMOTE_HOST', '')),
103 urlreq.quote(self.req.env.get('REMOTE_USER', ''))) 103 urlreq.quote(self.req.env.get('REMOTE_USER', '')))
104 104
105 def responsetype(self, v1compressible=False): 105 def responsetype(self, prefer_uncompressed):
106 """Determine the appropriate response type and compression settings. 106 """Determine the appropriate response type and compression settings.
107
108 The ``v1compressible`` argument states whether the response with
109 application/mercurial-0.1 media types should be zlib compressed.
110 107
111 Returns a tuple of (mediatype, compengine, engineopts). 108 Returns a tuple of (mediatype, compengine, engineopts).
112 """ 109 """
113 # For now, if it isn't compressible in the old world, it's never
114 # compressible. We can change this to send uncompressed 0.2 payloads
115 # later.
116 if not v1compressible:
117 return HGTYPE, None, None
118
119 # Determine the response media type and compression engine based 110 # Determine the response media type and compression engine based
120 # on the request parameters. 111 # on the request parameters.
121 protocaps = decodevaluefromheaders(self.req, r'X-HgProto').split(' ') 112 protocaps = decodevaluefromheaders(self.req, r'X-HgProto').split(' ')
122 113
123 if '0.2' in protocaps: 114 if '0.2' in protocaps:
115 # All clients are expected to support uncompressed data.
116 if prefer_uncompressed:
117 return HGTYPE2, util._noopengine(), {}
118
124 # Default as defined by wire protocol spec. 119 # Default as defined by wire protocol spec.
125 compformats = ['zlib', 'none'] 120 compformats = ['zlib', 'none']
126 for cap in protocaps: 121 for cap in protocaps:
127 if cap.startswith('comp='): 122 if cap.startswith('comp='):
128 compformats = cap[5:].split(',') 123 compformats = cap[5:].split(',')
153 return cmd in wireproto.commands 148 return cmd in wireproto.commands
154 149
155 def call(repo, req, cmd): 150 def call(repo, req, cmd):
156 p = webproto(req, repo.ui) 151 p = webproto(req, repo.ui)
157 152
158 def genversion2(gen, compress, engine, engineopts): 153 def genversion2(gen, engine, engineopts):
159 # application/mercurial-0.2 always sends a payload header 154 # application/mercurial-0.2 always sends a payload header
160 # identifying the compression engine. 155 # identifying the compression engine.
161 name = engine.wireprotosupport().name 156 name = engine.wireprotosupport().name
162 assert 0 < len(name) < 256 157 assert 0 < len(name) < 256
163 yield struct.pack('B', len(name)) 158 yield struct.pack('B', len(name))
164 yield name 159 yield name
165 160
166 if compress: 161 for chunk in gen:
167 for chunk in engine.compressstream(gen, opts=engineopts): 162 yield chunk
168 yield chunk
169 else:
170 for chunk in gen:
171 yield chunk
172 163
173 rsp = wireproto.dispatch(repo, p, cmd) 164 rsp = wireproto.dispatch(repo, p, cmd)
174 if isinstance(rsp, bytes): 165 if isinstance(rsp, bytes):
175 req.respond(HTTP_OK, HGTYPE, body=rsp) 166 req.respond(HTTP_OK, HGTYPE, body=rsp)
176 return [] 167 return []
168 elif isinstance(rsp, wireproto.streamres_legacy):
169 gen = rsp.gen
170 req.respond(HTTP_OK, HGTYPE)
171 return gen
177 elif isinstance(rsp, wireproto.streamres): 172 elif isinstance(rsp, wireproto.streamres):
178 gen = rsp.gen 173 gen = rsp.gen
179 174
180 # This code for compression should not be streamres specific. It 175 # This code for compression should not be streamres specific. It
181 # is here because we only compress streamres at the moment. 176 # is here because we only compress streamres at the moment.
182 mediatype, engine, engineopts = p.responsetype(rsp.v1compressible) 177 mediatype, engine, engineopts = p.responsetype(rsp.prefer_uncompressed)
183 178 gen = engine.compressstream(gen, engineopts)
184 if mediatype == HGTYPE and rsp.v1compressible: 179
185 gen = engine.compressstream(gen, engineopts) 180 if mediatype == HGTYPE2:
186 elif mediatype == HGTYPE2: 181 gen = genversion2(gen, engine, engineopts)
187 gen = genversion2(gen, rsp.v1compressible, engine, engineopts)
188 182
189 req.respond(HTTP_OK, mediatype) 183 req.respond(HTTP_OK, mediatype)
190 return gen 184 return gen
191 elif isinstance(rsp, wireproto.pushres): 185 elif isinstance(rsp, wireproto.pushres):
192 val = p.restore() 186 val = p.restore()