Mercurial > public > mercurial-scm > hg
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() |