| | varnish-cache/bin/varnishd/cache/cache_gzip.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2013-2015 Varnish Software AS |
2 |
|
* All rights reserved. |
3 |
|
* |
4 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
5 |
|
* |
6 |
|
* SPDX-License-Identifier: BSD-2-Clause |
7 |
|
* |
8 |
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
* modification, are permitted provided that the following conditions |
10 |
|
* are met: |
11 |
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
* documentation and/or other materials provided with the distribution. |
16 |
|
* |
17 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
18 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
21 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
25 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
26 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
27 |
|
* SUCH DAMAGE. |
28 |
|
* |
29 |
|
* Interaction with the libvgz (zlib) library. |
30 |
|
* |
31 |
|
* The zlib library pollutes namespace a LOT when you include the "vgz.h" |
32 |
|
* (aka "zlib.h") file so we contain the damage by vectoring all access |
33 |
|
* to libz through this source file. |
34 |
|
* |
35 |
|
* The API defined by this file, will also insulate the rest of the code, |
36 |
|
* should we find a better gzip library at a later date. |
37 |
|
* |
38 |
|
*/ |
39 |
|
|
40 |
|
#include "config.h" |
41 |
|
|
42 |
|
#include <stdlib.h> |
43 |
|
|
44 |
|
#include "cache_varnishd.h" |
45 |
|
#include "cache_filter.h" |
46 |
|
#include "cache_objhead.h" |
47 |
|
#include "cache_vgz.h" |
48 |
|
|
49 |
|
#include "storage/storage.h" |
50 |
|
|
51 |
|
#include "vend.h" |
52 |
|
|
53 |
|
#include "vgz.h" |
54 |
|
|
55 |
|
struct vgz { |
56 |
|
unsigned magic; |
57 |
|
#define VGZ_MAGIC 0x162df0cb |
58 |
|
enum {VGZ_GZ,VGZ_UN} dir; |
59 |
|
struct vsl_log *vsl; |
60 |
|
const char *id; |
61 |
|
int last_i; |
62 |
|
enum vgz_flag flag; |
63 |
|
|
64 |
|
struct stv_buffer *stvbuf; |
65 |
|
char *m_buf; |
66 |
|
ssize_t m_sz; |
67 |
|
ssize_t m_len; |
68 |
|
|
69 |
|
intmax_t bits; |
70 |
|
|
71 |
|
z_stream vz; |
72 |
|
}; |
73 |
|
|
74 |
|
static const char * |
75 |
240 |
vgz_msg(const struct vgz *vg) |
76 |
|
{ |
77 |
240 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
78 |
240 |
return (vg->vz.msg ? vg->vz.msg : "(null)"); |
79 |
|
} |
80 |
|
|
81 |
|
/*-------------------------------------------------------------------- |
82 |
|
* Set up a gunzip instance |
83 |
|
*/ |
84 |
|
|
85 |
|
static struct vgz * |
86 |
9240 |
vgz_gunzip(struct vsl_log *vsl, const char *id) |
87 |
|
{ |
88 |
|
struct vgz *vg; |
89 |
|
|
90 |
9240 |
ALLOC_OBJ(vg, VGZ_MAGIC); |
91 |
9240 |
AN(vg); |
92 |
9240 |
vg->vsl = vsl; |
93 |
9240 |
vg->id = id; |
94 |
9240 |
vg->dir = VGZ_UN; |
95 |
|
|
96 |
|
/* |
97 |
|
* Max memory usage according to zonf.h: |
98 |
|
* mem_needed = "a few kb" + (1 << (windowBits)) |
99 |
|
* Since we don't control windowBits, we have to assume |
100 |
|
* it is 15, so 34-35KB or so. |
101 |
|
*/ |
102 |
9240 |
assert(Z_OK == inflateInit2(&vg->vz, 31)); |
103 |
9240 |
return (vg); |
104 |
|
} |
105 |
|
|
106 |
|
static struct vgz * |
107 |
8040 |
VGZ_NewGunzip(struct vsl_log *vsl, const char *id) |
108 |
|
{ |
109 |
8040 |
VSC_C_main->n_gunzip++; |
110 |
8040 |
return (vgz_gunzip(vsl, id)); |
111 |
|
} |
112 |
|
|
113 |
|
static struct vgz * |
114 |
1200 |
VGZ_NewTestGunzip(struct vsl_log *vsl, const char *id) |
115 |
|
{ |
116 |
1200 |
VSC_C_main->n_test_gunzip++; |
117 |
1200 |
return (vgz_gunzip(vsl, id)); |
118 |
|
} |
119 |
|
|
120 |
|
struct vgz * |
121 |
3680 |
VGZ_NewGzip(struct vsl_log *vsl, const char *id) |
122 |
|
{ |
123 |
|
struct vgz *vg; |
124 |
|
int i; |
125 |
|
|
126 |
3680 |
VSC_C_main->n_gzip++; |
127 |
3680 |
ALLOC_OBJ(vg, VGZ_MAGIC); |
128 |
3680 |
AN(vg); |
129 |
3680 |
vg->vsl = vsl; |
130 |
3680 |
vg->id = id; |
131 |
3680 |
vg->dir = VGZ_GZ; |
132 |
|
|
133 |
|
/* |
134 |
|
* From zconf.h: |
135 |
|
* |
136 |
|
* mem_needed = "a few kb" |
137 |
|
* + (1 << (windowBits+2)) |
138 |
|
* + (1 << (memLevel+9)) |
139 |
|
* |
140 |
|
* windowBits [8..15] (-> 1K..128K) |
141 |
|
* memLevel [1..9] (-> 1K->256K) |
142 |
|
*/ |
143 |
3680 |
i = deflateInit2(&vg->vz, |
144 |
|
cache_param->gzip_level, /* Level */ |
145 |
|
Z_DEFLATED, /* Method */ |
146 |
|
16 + 15, /* Window bits (16=gzip) */ |
147 |
|
cache_param->gzip_memlevel, /* memLevel */ |
148 |
|
Z_DEFAULT_STRATEGY); |
149 |
3680 |
assert(Z_OK == i); |
150 |
3680 |
return (vg); |
151 |
|
} |
152 |
|
|
153 |
|
/*-------------------------------------------------------------------- |
154 |
|
*/ |
155 |
|
|
156 |
|
static int |
157 |
9880 |
vgz_getmbuf(struct worker *wrk, struct vgz *vg) |
158 |
|
{ |
159 |
|
size_t sz; |
160 |
|
|
161 |
9880 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
162 |
9880 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
163 |
9880 |
AZ(vg->m_sz); |
164 |
9880 |
AZ(vg->m_len); |
165 |
9880 |
AZ(vg->m_buf); |
166 |
9880 |
AZ(vg->stvbuf); |
167 |
|
|
168 |
9880 |
vg->stvbuf = STV_AllocBuf(wrk, stv_transient, cache_param->gzip_buffer); |
169 |
9880 |
if (vg->stvbuf == NULL) |
170 |
0 |
return (-1); |
171 |
9880 |
vg->m_buf = STV_GetBufPtr(vg->stvbuf, &sz); |
172 |
9880 |
vg->m_sz = sz; |
173 |
9880 |
AN(vg->m_buf); |
174 |
9880 |
assert(vg->m_sz > 0); |
175 |
9880 |
return (0); |
176 |
9880 |
} |
177 |
|
|
178 |
|
/*--------------------------------------------------------------------*/ |
179 |
|
|
180 |
|
void |
181 |
67048 |
VGZ_Ibuf(struct vgz *vg, const void *ptr, ssize_t len) |
182 |
|
{ |
183 |
|
|
184 |
67048 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
185 |
67048 |
AZ(vg->vz.avail_in); |
186 |
67048 |
assert(len >= 0); |
187 |
67048 |
if (len > 0) |
188 |
45008 |
AN(ptr); |
189 |
|
|
190 |
67048 |
vg->vz.next_in = TRUST_ME(ptr); |
191 |
67048 |
vg->vz.avail_in = len; |
192 |
67048 |
} |
193 |
|
|
194 |
|
int |
195 |
150941 |
VGZ_IbufEmpty(const struct vgz *vg) |
196 |
|
{ |
197 |
|
|
198 |
150941 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
199 |
150941 |
return (vg->vz.avail_in == 0); |
200 |
|
} |
201 |
|
|
202 |
|
/*--------------------------------------------------------------------*/ |
203 |
|
|
204 |
|
void |
205 |
71096 |
VGZ_Obuf(struct vgz *vg, void *ptr, ssize_t len) |
206 |
|
{ |
207 |
|
|
208 |
71096 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
209 |
71096 |
AN(ptr); |
210 |
71096 |
assert(len > 0); |
211 |
|
|
212 |
71096 |
vg->vz.next_out = ptr; |
213 |
71096 |
vg->vz.avail_out = len; |
214 |
71096 |
} |
215 |
|
|
216 |
|
int |
217 |
42837 |
VGZ_ObufFull(const struct vgz *vg) |
218 |
|
{ |
219 |
|
|
220 |
42837 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
221 |
42837 |
return (vg->vz.avail_out == 0); |
222 |
|
} |
223 |
|
|
224 |
|
/*--------------------------------------------------------------------*/ |
225 |
|
|
226 |
|
static enum vgzret_e |
227 |
32739 |
VGZ_Gunzip(struct vgz *vg, const void **pptr, ssize_t *plen) |
228 |
|
{ |
229 |
|
int i; |
230 |
|
ssize_t l; |
231 |
|
const uint8_t *before; |
232 |
|
|
233 |
32739 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
234 |
|
|
235 |
32739 |
*pptr = NULL; |
236 |
32739 |
*plen = 0; |
237 |
32739 |
AN(vg->vz.next_out); |
238 |
32739 |
AN(vg->vz.avail_out); |
239 |
32739 |
before = vg->vz.next_out; |
240 |
32739 |
i = inflate(&vg->vz, 0); |
241 |
32739 |
if (i == Z_OK || i == Z_STREAM_END) { |
242 |
32579 |
*pptr = before; |
243 |
32579 |
l = (const uint8_t *)vg->vz.next_out - before; |
244 |
32579 |
*plen = l; |
245 |
32579 |
} |
246 |
32739 |
vg->last_i = i; |
247 |
32739 |
if (i == Z_OK) |
248 |
22659 |
return (VGZ_OK); |
249 |
10080 |
if (i == Z_STREAM_END) |
250 |
9920 |
return (VGZ_END); |
251 |
160 |
if (i == Z_BUF_ERROR) |
252 |
80 |
return (VGZ_STUCK); |
253 |
80 |
VSLb(vg->vsl, SLT_Gzip, "Gunzip error: %d (%s)", i, vgz_msg(vg)); |
254 |
80 |
return (VGZ_ERROR); |
255 |
32739 |
} |
256 |
|
|
257 |
|
/*--------------------------------------------------------------------*/ |
258 |
|
|
259 |
|
enum vgzret_e |
260 |
45517 |
VGZ_Gzip(struct vgz *vg, const void **pptr, ssize_t *plen, enum vgz_flag flags) |
261 |
|
{ |
262 |
|
int i; |
263 |
|
int zflg; |
264 |
|
ssize_t l; |
265 |
|
const uint8_t *before; |
266 |
|
|
267 |
45517 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
268 |
|
|
269 |
45517 |
*pptr = NULL; |
270 |
45517 |
*plen = 0; |
271 |
45517 |
AN(vg->vz.next_out); |
272 |
45517 |
AN(vg->vz.avail_out); |
273 |
45517 |
before = vg->vz.next_out; |
274 |
45517 |
switch (flags) { |
275 |
29997 |
case VGZ_NORMAL: zflg = Z_NO_FLUSH; break; |
276 |
5000 |
case VGZ_ALIGN: zflg = Z_SYNC_FLUSH; break; |
277 |
5040 |
case VGZ_RESET: zflg = Z_FULL_FLUSH; break; |
278 |
5480 |
case VGZ_FINISH: zflg = Z_FINISH; break; |
279 |
0 |
default: WRONG("Invalid VGZ flag"); |
280 |
0 |
} |
281 |
45517 |
i = deflate(&vg->vz, zflg); |
282 |
45517 |
if (i == Z_OK || i == Z_STREAM_END) { |
283 |
45517 |
*pptr = before; |
284 |
45517 |
l = (const uint8_t *)vg->vz.next_out - before; |
285 |
45517 |
*plen = l; |
286 |
45517 |
} |
287 |
45517 |
vg->last_i = i; |
288 |
45517 |
if (i == Z_OK) |
289 |
42037 |
return (VGZ_OK); |
290 |
3480 |
if (i == Z_STREAM_END) |
291 |
3480 |
return (VGZ_END); |
292 |
0 |
if (i == Z_BUF_ERROR) |
293 |
0 |
return (VGZ_STUCK); |
294 |
0 |
VSLb(vg->vsl, SLT_Gzip, "Gzip error: %d (%s)", i, vgz_msg(vg)); |
295 |
0 |
return (VGZ_ERROR); |
296 |
45517 |
} |
297 |
|
|
298 |
|
/*-------------------------------------------------------------------- |
299 |
|
* VDP for gunzip'ing |
300 |
|
*/ |
301 |
|
|
302 |
|
static int v_matchproto_(vdp_init_f) |
303 |
3040 |
vdp_gunzip_init(VRT_CTX, struct vdp_ctx *vdc, void **priv) |
304 |
|
{ |
305 |
|
struct vgz *vg; |
306 |
|
struct boc *boc; |
307 |
|
enum boc_state_e bos; |
308 |
|
const char *p; |
309 |
|
ssize_t dl; |
310 |
|
uint64_t u; |
311 |
|
|
312 |
3040 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
313 |
3040 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
314 |
3040 |
CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC); |
315 |
3040 |
CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC); |
316 |
3040 |
AN(vdc->clen); |
317 |
3040 |
AN(priv); |
318 |
|
|
319 |
3040 |
vg = VGZ_NewGunzip(vdc->vsl, "U D -"); |
320 |
3040 |
AN(vg); |
321 |
3040 |
if (vgz_getmbuf(vdc->wrk, vg)) { |
322 |
0 |
(void)VGZ_Destroy(vdc->wrk, &vg); |
323 |
0 |
return (-1); |
324 |
|
} |
325 |
|
|
326 |
3040 |
VGZ_Obuf(vg, vg->m_buf, vg->m_sz); |
327 |
3040 |
*priv = vg; |
328 |
|
|
329 |
3040 |
http_Unset(vdc->hp, H_Content_Encoding); |
330 |
|
|
331 |
3040 |
*vdc->clen = -1; |
332 |
|
|
333 |
3040 |
if (vdc->oc == NULL) |
334 |
680 |
return (0); |
335 |
|
|
336 |
2360 |
boc = HSH_RefBoc(vdc->oc); |
337 |
2360 |
if (boc != NULL) { |
338 |
440 |
CHECK_OBJ(boc, BOC_MAGIC); |
339 |
440 |
bos = boc->state; |
340 |
440 |
HSH_DerefBoc(vdc->wrk, vdc->oc); |
341 |
440 |
if (bos < BOS_FINISHED) |
342 |
440 |
return (0); /* OA_GZIPBITS is not stable yet */ |
343 |
0 |
} |
344 |
|
|
345 |
1920 |
p = ObjGetAttr(vdc->wrk, vdc->oc, OA_GZIPBITS, &dl); |
346 |
1920 |
if (p != NULL && dl == 32) { |
347 |
1920 |
u = vbe64dec(p + 24); |
348 |
1920 |
if (u != 0) |
349 |
1880 |
*vdc->clen = u; |
350 |
1920 |
} |
351 |
1920 |
return (0); |
352 |
3040 |
} |
353 |
|
|
354 |
|
static int v_matchproto_(vdp_fini_f) |
355 |
3040 |
vdp_gunzip_fini(struct vdp_ctx *vdc, void **priv) |
356 |
|
{ |
357 |
|
struct vgz *vg; |
358 |
|
|
359 |
3040 |
(void)vdc; |
360 |
3040 |
TAKE_OBJ_NOTNULL(vg, priv, VGZ_MAGIC); |
361 |
3040 |
AN(vg->m_buf); |
362 |
3040 |
(void)VGZ_Destroy(vdc->wrk, &vg); |
363 |
3040 |
return (0); |
364 |
|
} |
365 |
|
|
366 |
|
static int v_matchproto_(vdp_bytes_f) |
367 |
17400 |
vdp_gunzip_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, |
368 |
|
const void *ptr, ssize_t len) |
369 |
|
{ |
370 |
|
enum vgzret_e vr; |
371 |
|
ssize_t dl; |
372 |
|
const void *dp; |
373 |
|
struct worker *wrk; |
374 |
|
struct vgz *vg; |
375 |
|
|
376 |
17400 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
377 |
17400 |
wrk = vdc->wrk; |
378 |
17400 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
379 |
17400 |
(void)act; |
380 |
|
|
381 |
17400 |
CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC); |
382 |
17400 |
AN(vg->m_buf); |
383 |
|
|
384 |
17400 |
if (len == 0) |
385 |
4680 |
return (0); |
386 |
|
|
387 |
12720 |
VGZ_Ibuf(vg, ptr, len); |
388 |
12720 |
do { |
389 |
12720 |
vr = VGZ_Gunzip(vg, &dp, &dl); |
390 |
12720 |
if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) { |
391 |
80 |
VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)", |
392 |
40 |
vr, "junk after VGZ_END"); |
393 |
40 |
return (-1); |
394 |
|
} |
395 |
12680 |
vg->m_len += dl; |
396 |
12680 |
if (vr < VGZ_OK) |
397 |
0 |
return (-1); |
398 |
12680 |
if (vg->m_len == vg->m_sz || vr != VGZ_OK) { |
399 |
5840 |
if (VDP_bytes(vdc, vr == VGZ_END ? VDP_END : VDP_FLUSH, |
400 |
2920 |
vg->m_buf, vg->m_len)) |
401 |
160 |
return (vdc->retval); |
402 |
2760 |
vg->m_len = 0; |
403 |
2760 |
VGZ_Obuf(vg, vg->m_buf, vg->m_sz); |
404 |
2760 |
} |
405 |
12520 |
} while (!VGZ_IbufEmpty(vg)); |
406 |
12520 |
assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END); |
407 |
12520 |
return (0); |
408 |
17400 |
} |
409 |
|
|
410 |
|
const struct vdp VDP_gunzip = { |
411 |
|
.name = "gunzip", |
412 |
|
.init = vdp_gunzip_init, |
413 |
|
.bytes = vdp_gunzip_bytes, |
414 |
|
.fini = vdp_gunzip_fini, |
415 |
|
}; |
416 |
|
|
417 |
|
/*--------------------------------------------------------------------*/ |
418 |
|
|
419 |
|
void |
420 |
50208 |
VGZ_UpdateObj(const struct vfp_ctx *vc, struct vgz *vg, enum vgzret_e e) |
421 |
|
{ |
422 |
|
char *p; |
423 |
|
intmax_t ii; |
424 |
|
|
425 |
50208 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
426 |
50208 |
if (e < VGZ_OK) |
427 |
0 |
return; |
428 |
50208 |
ii = vg->vz.start_bit + vg->vz.last_bit + vg->vz.stop_bit; |
429 |
50208 |
if (e != VGZ_END && ii == vg->bits) |
430 |
36917 |
return; |
431 |
13291 |
vg->bits = ii; |
432 |
13291 |
p = ObjSetAttr(vc->wrk, vc->oc, OA_GZIPBITS, 32, NULL); |
433 |
13291 |
AN(p); |
434 |
13291 |
vbe64enc(p, vg->vz.start_bit); |
435 |
13291 |
vbe64enc(p + 8, vg->vz.last_bit); |
436 |
13291 |
vbe64enc(p + 16, vg->vz.stop_bit); |
437 |
13291 |
if (e != VGZ_END) |
438 |
5091 |
return; |
439 |
8200 |
if (vg->dir == VGZ_GZ) |
440 |
6960 |
vbe64enc(p + 24, vg->vz.total_in); |
441 |
8200 |
if (vg->dir == VGZ_UN) |
442 |
1240 |
vbe64enc(p + 24, vg->vz.total_out); |
443 |
50208 |
} |
444 |
|
|
445 |
|
/*-------------------------------------------------------------------- |
446 |
|
*/ |
447 |
|
|
448 |
|
enum vgzret_e |
449 |
12920 |
VGZ_Destroy(struct worker *wrk, struct vgz **vgp) |
450 |
|
{ |
451 |
|
struct vgz *vg; |
452 |
|
enum vgzret_e vr; |
453 |
|
int i; |
454 |
|
|
455 |
12920 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
456 |
12920 |
TAKE_OBJ_NOTNULL(vg, vgp, VGZ_MAGIC); |
457 |
12920 |
AN(vg->id); |
458 |
25840 |
VSLb(vg->vsl, SLT_Gzip, "%s %jd %jd %jd %jd %jd", |
459 |
12920 |
vg->id, |
460 |
12920 |
(intmax_t)vg->vz.total_in, |
461 |
12920 |
(intmax_t)vg->vz.total_out, |
462 |
12920 |
(intmax_t)vg->vz.start_bit, |
463 |
12920 |
(intmax_t)vg->vz.last_bit, |
464 |
12920 |
(intmax_t)vg->vz.stop_bit); |
465 |
12920 |
if (vg->dir == VGZ_GZ) |
466 |
3680 |
i = deflateEnd(&vg->vz); |
467 |
|
else |
468 |
9240 |
i = inflateEnd(&vg->vz); |
469 |
12920 |
if (vg->last_i == Z_STREAM_END && i == Z_OK) |
470 |
10320 |
i = Z_STREAM_END; |
471 |
12920 |
if (vg->m_buf != NULL) { |
472 |
9880 |
AN(vg->stvbuf); |
473 |
9880 |
STV_FreeBuf(wrk, &vg->stvbuf); |
474 |
9880 |
} |
475 |
12920 |
AZ(vg->stvbuf); |
476 |
12920 |
if (i == Z_OK) |
477 |
2520 |
vr = VGZ_OK; |
478 |
10400 |
else if (i == Z_STREAM_END) |
479 |
10320 |
vr = VGZ_END; |
480 |
80 |
else if (i == Z_BUF_ERROR) |
481 |
0 |
vr = VGZ_STUCK; |
482 |
|
else { |
483 |
160 |
VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)", |
484 |
80 |
i, vgz_msg(vg)); |
485 |
80 |
vr = VGZ_ERROR; |
486 |
|
} |
487 |
12920 |
FREE_OBJ(vg); |
488 |
12920 |
return (vr); |
489 |
|
} |
490 |
|
|
491 |
|
/*--------------------------------------------------------------------*/ |
492 |
|
|
493 |
|
static enum vfp_status v_matchproto_(vfp_init_f) |
494 |
7000 |
vfp_gzip_init(VRT_CTX, struct vfp_ctx *vc, struct vfp_entry *vfe) |
495 |
|
{ |
496 |
|
struct vgz *vg; |
497 |
|
|
498 |
7000 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
499 |
7000 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
500 |
7000 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
501 |
|
|
502 |
|
/* |
503 |
|
* G(un)zip makes no sence on partial responses, but since |
504 |
|
* it is an pure 1:1 transform, we can just ignore it. |
505 |
|
*/ |
506 |
7000 |
if (http_GetStatus(vc->resp) == 206) |
507 |
160 |
return (VFP_NULL); |
508 |
|
|
509 |
6840 |
if (vfe->vfp == &VFP_gzip) { |
510 |
640 |
if (http_GetHdr(vc->resp, H_Content_Encoding, NULL)) |
511 |
0 |
return (VFP_NULL); |
512 |
640 |
vg = VGZ_NewGzip(vc->wrk->vsl, vfe->vfp->priv1); |
513 |
640 |
vc->obj_flags |= OF_GZIPED | OF_CHGCE; |
514 |
640 |
} else { |
515 |
6200 |
if (!http_HdrIs(vc->resp, H_Content_Encoding, "gzip")) |
516 |
0 |
return (VFP_NULL); |
517 |
6200 |
if (vfe->vfp == &VFP_gunzip) { |
518 |
5000 |
vg = VGZ_NewGunzip(vc->wrk->vsl, vfe->vfp->priv1); |
519 |
5000 |
vc->obj_flags &= ~OF_GZIPED; |
520 |
5000 |
vc->obj_flags |= OF_CHGCE; |
521 |
5000 |
} else { |
522 |
1200 |
vg = VGZ_NewTestGunzip(vc->wrk->vsl, vfe->vfp->priv1); |
523 |
1200 |
vc->obj_flags |= OF_GZIPED; |
524 |
|
} |
525 |
|
} |
526 |
6840 |
AN(vg); |
527 |
6840 |
vfe->priv1 = vg; |
528 |
6840 |
if (vgz_getmbuf(vc->wrk, vg)) |
529 |
0 |
return (VFP_ERROR); |
530 |
6840 |
VGZ_Ibuf(vg, vg->m_buf, 0); |
531 |
6840 |
AZ(vg->m_len); |
532 |
|
|
533 |
6840 |
if (vfe->vfp == &VFP_gunzip || vfe->vfp == &VFP_gzip) { |
534 |
5640 |
http_Unset(vc->resp, H_Content_Encoding); |
535 |
5640 |
http_Unset(vc->resp, H_Content_Length); |
536 |
5640 |
RFC2616_Weaken_Etag(vc->resp); |
537 |
5640 |
} |
538 |
|
|
539 |
6840 |
if (vfe->vfp == &VFP_gzip) |
540 |
640 |
http_SetHeader(vc->resp, "Content-Encoding: gzip"); |
541 |
|
|
542 |
6840 |
if (vfe->vfp == &VFP_gzip || vfe->vfp == &VFP_testgunzip) |
543 |
1840 |
RFC2616_Vary_AE(vc->resp); |
544 |
|
|
545 |
6840 |
return (VFP_OK); |
546 |
7000 |
} |
547 |
|
|
548 |
|
/*-------------------------------------------------------------------- |
549 |
|
* VFP_GUNZIP |
550 |
|
* |
551 |
|
* A VFP for gunzip'ing an object as we receive it from the backend |
552 |
|
*/ |
553 |
|
|
554 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
555 |
18448 |
vfp_gunzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
556 |
|
ssize_t *lp) |
557 |
|
{ |
558 |
|
ssize_t l; |
559 |
|
struct vgz *vg; |
560 |
18448 |
enum vgzret_e vr = VGZ_ERROR; |
561 |
|
const void *dp; |
562 |
|
ssize_t dl; |
563 |
18448 |
enum vfp_status vp = VFP_OK; |
564 |
|
|
565 |
18448 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
566 |
18448 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
567 |
18448 |
CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); |
568 |
18448 |
AN(p); |
569 |
18448 |
AN(lp); |
570 |
18448 |
l = *lp; |
571 |
18448 |
*lp = 0; |
572 |
18448 |
VGZ_Obuf(vg, p, l); |
573 |
18448 |
do { |
574 |
18528 |
if (VGZ_IbufEmpty(vg)) { |
575 |
5800 |
l = vg->m_sz; |
576 |
5800 |
vp = VFP_Suck(vc, vg->m_buf, &l); |
577 |
5800 |
if (vp == VFP_ERROR) |
578 |
0 |
return (vp); |
579 |
5800 |
VGZ_Ibuf(vg, vg->m_buf, l); |
580 |
5800 |
} |
581 |
18528 |
if (!VGZ_IbufEmpty(vg) || vp == VFP_END) { |
582 |
18528 |
vr = VGZ_Gunzip(vg, &dp, &dl); |
583 |
18528 |
if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) |
584 |
40 |
return (VFP_Error(vc, "Junk after gzip data")); |
585 |
18488 |
if (vr < VGZ_OK) |
586 |
160 |
return (VFP_Error(vc, |
587 |
80 |
"Invalid Gzip data: %s", vgz_msg(vg))); |
588 |
18408 |
if (dl > 0) { |
589 |
15528 |
*lp = dl; |
590 |
15528 |
assert(dp == p); |
591 |
15528 |
return (VFP_OK); |
592 |
|
} |
593 |
2880 |
} |
594 |
2880 |
AN(VGZ_IbufEmpty(vg)); |
595 |
2880 |
} while (vp == VFP_OK); |
596 |
2800 |
if (vr != VGZ_END) |
597 |
40 |
return (VFP_Error(vc, "Gunzip error at the very end")); |
598 |
2760 |
return (vp); |
599 |
18448 |
} |
600 |
|
|
601 |
|
|
602 |
|
/*-------------------------------------------------------------------- |
603 |
|
* VFP_GZIP |
604 |
|
* |
605 |
|
* A VFP for gzip'ing an object as we receive it from the backend |
606 |
|
*/ |
607 |
|
|
608 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
609 |
2520 |
vfp_gzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
610 |
|
ssize_t *lp) |
611 |
|
{ |
612 |
|
ssize_t l; |
613 |
|
struct vgz *vg; |
614 |
2520 |
enum vgzret_e vr = VGZ_ERROR; |
615 |
|
const void *dp; |
616 |
|
ssize_t dl; |
617 |
2520 |
enum vfp_status vp = VFP_ERROR; |
618 |
|
|
619 |
2520 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
620 |
2520 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
621 |
2520 |
CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); |
622 |
2520 |
AN(p); |
623 |
2520 |
AN(lp); |
624 |
2520 |
l = *lp; |
625 |
2520 |
*lp = 0; |
626 |
2520 |
VGZ_Obuf(vg, p, l); |
627 |
2520 |
do { |
628 |
2680 |
if (VGZ_IbufEmpty(vg)) { |
629 |
2520 |
l = vg->m_sz; |
630 |
2520 |
vp = VFP_Suck(vc, vg->m_buf, &l); |
631 |
2520 |
if (vp == VFP_ERROR) |
632 |
0 |
break; |
633 |
2520 |
if (vp == VFP_END) |
634 |
880 |
vg->flag = VGZ_FINISH; |
635 |
2520 |
VGZ_Ibuf(vg, vg->m_buf, l); |
636 |
2520 |
} |
637 |
2680 |
if (!VGZ_IbufEmpty(vg) || vg->flag == VGZ_FINISH) { |
638 |
2680 |
vr = VGZ_Gzip(vg, &dp, &dl, vg->flag); |
639 |
2680 |
if (vr < VGZ_OK) |
640 |
0 |
return (VFP_Error(vc, "Gzip failed")); |
641 |
2680 |
if (dl > 0) { |
642 |
2520 |
VGZ_UpdateObj(vc, vg, vr); |
643 |
2520 |
*lp = dl; |
644 |
2520 |
assert(dp == p); |
645 |
2520 |
if (vr != VGZ_END || !VGZ_IbufEmpty(vg)) |
646 |
1920 |
return (VFP_OK); |
647 |
600 |
} |
648 |
760 |
} |
649 |
760 |
AN(VGZ_IbufEmpty(vg)); |
650 |
760 |
} while (vg->flag != VGZ_FINISH); |
651 |
|
|
652 |
600 |
if (vr != VGZ_END) |
653 |
0 |
return (VFP_Error(vc, "Gzip failed")); |
654 |
600 |
VGZ_UpdateObj(vc, vg, VGZ_END); |
655 |
600 |
return (VFP_END); |
656 |
2520 |
} |
657 |
|
|
658 |
|
/*-------------------------------------------------------------------- |
659 |
|
* VFP_TESTGZIP |
660 |
|
* |
661 |
|
* A VFP for testing that received gzip data is valid, and for |
662 |
|
* collecting the magic bits while we're at it. |
663 |
|
*/ |
664 |
|
|
665 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
666 |
1571 |
vfp_testgunzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
667 |
|
ssize_t *lp) |
668 |
|
{ |
669 |
|
struct vgz *vg; |
670 |
1571 |
enum vgzret_e vr = VGZ_ERROR; |
671 |
|
const void *dp; |
672 |
|
ssize_t dl; |
673 |
|
enum vfp_status vp; |
674 |
|
|
675 |
1571 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
676 |
1571 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
677 |
1571 |
CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); |
678 |
1571 |
AN(p); |
679 |
1571 |
AN(lp); |
680 |
1571 |
vp = VFP_Suck(vc, p, lp); |
681 |
1571 |
if (vp == VFP_ERROR) |
682 |
80 |
return (vp); |
683 |
1491 |
if (*lp > 0 || vp == VFP_END) { |
684 |
1491 |
VGZ_Ibuf(vg, p, *lp); |
685 |
1491 |
do { |
686 |
1491 |
VGZ_Obuf(vg, vg->m_buf, vg->m_sz); |
687 |
1491 |
vr = VGZ_Gunzip(vg, &dp, &dl); |
688 |
1491 |
if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) |
689 |
120 |
return (VFP_Error(vc, "Junk after gzip data")); |
690 |
1371 |
if (vr < VGZ_OK) |
691 |
0 |
return (VFP_Error(vc, |
692 |
0 |
"Invalid Gzip data: %s", vgz_msg(vg))); |
693 |
1371 |
} while (!VGZ_IbufEmpty(vg)); |
694 |
1371 |
} |
695 |
1371 |
VGZ_UpdateObj(vc, vg, vr); |
696 |
1371 |
if (vp == VFP_END && vr != VGZ_END) |
697 |
40 |
return (VFP_Error(vc, "tGunzip failed")); |
698 |
1331 |
return (vp); |
699 |
1571 |
} |
700 |
|
|
701 |
|
/*--------------------------------------------------------------------*/ |
702 |
|
|
703 |
|
static void v_matchproto_(vfp_fini_f) |
704 |
7440 |
vfp_gzip_fini(struct vfp_ctx *vc, struct vfp_entry *vfe) |
705 |
|
{ |
706 |
|
struct vgz *vg; |
707 |
|
|
708 |
7440 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
709 |
7440 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
710 |
|
|
711 |
7440 |
if (vfe->priv1 != NULL) { |
712 |
6840 |
TAKE_OBJ_NOTNULL(vg, &vfe->priv1, VGZ_MAGIC); |
713 |
6840 |
(void)VGZ_Destroy(vc->wrk, &vg); |
714 |
6840 |
} |
715 |
7440 |
} |
716 |
|
|
717 |
|
/*--------------------------------------------------------------------*/ |
718 |
|
|
719 |
|
const struct vfp VFP_gunzip = { |
720 |
|
.name = "gunzip", |
721 |
|
.init = vfp_gzip_init, |
722 |
|
.pull = vfp_gunzip_pull, |
723 |
|
.fini = vfp_gzip_fini, |
724 |
|
.priv1 = "U F -", |
725 |
|
}; |
726 |
|
|
727 |
|
const struct vfp VFP_gzip = { |
728 |
|
.name = "gzip", |
729 |
|
.init = vfp_gzip_init, |
730 |
|
.pull = vfp_gzip_pull, |
731 |
|
.fini = vfp_gzip_fini, |
732 |
|
.priv1 = "G F -", |
733 |
|
}; |
734 |
|
|
735 |
|
const struct vfp VFP_testgunzip = { |
736 |
|
.name = "testgunzip", |
737 |
|
.init = vfp_gzip_init, |
738 |
|
.pull = vfp_testgunzip_pull, |
739 |
|
.fini = vfp_gzip_fini, |
740 |
|
.priv1 = "u F -", |
741 |
|
}; |