| | 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 |
|
#include "vend.h" |
49 |
|
|
50 |
|
#include "vgz.h" |
51 |
|
|
52 |
|
struct vgz { |
53 |
|
unsigned magic; |
54 |
|
#define VGZ_MAGIC 0x162df0cb |
55 |
|
enum {VGZ_GZ,VGZ_UN} dir; |
56 |
|
struct vsl_log *vsl; |
57 |
|
const char *id; |
58 |
|
int last_i; |
59 |
|
enum vgz_flag flag; |
60 |
|
|
61 |
|
char *m_buf; |
62 |
|
ssize_t m_sz; |
63 |
|
ssize_t m_len; |
64 |
|
|
65 |
|
intmax_t bits; |
66 |
|
|
67 |
|
z_stream vz; |
68 |
|
}; |
69 |
|
|
70 |
|
static const char * |
71 |
240 |
vgz_msg(const struct vgz *vg) |
72 |
|
{ |
73 |
240 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
74 |
240 |
return (vg->vz.msg ? vg->vz.msg : "(null)"); |
75 |
|
} |
76 |
|
|
77 |
|
/*-------------------------------------------------------------------- |
78 |
|
* Set up a gunzip instance |
79 |
|
*/ |
80 |
|
|
81 |
|
static struct vgz * |
82 |
9240 |
vgz_gunzip(struct vsl_log *vsl, const char *id) |
83 |
|
{ |
84 |
|
struct vgz *vg; |
85 |
|
|
86 |
9240 |
ALLOC_OBJ(vg, VGZ_MAGIC); |
87 |
9240 |
AN(vg); |
88 |
9240 |
vg->vsl = vsl; |
89 |
9240 |
vg->id = id; |
90 |
9240 |
vg->dir = VGZ_UN; |
91 |
|
|
92 |
|
/* |
93 |
|
* Max memory usage according to zonf.h: |
94 |
|
* mem_needed = "a few kb" + (1 << (windowBits)) |
95 |
|
* Since we don't control windowBits, we have to assume |
96 |
|
* it is 15, so 34-35KB or so. |
97 |
|
*/ |
98 |
9240 |
assert(Z_OK == inflateInit2(&vg->vz, 31)); |
99 |
9240 |
return (vg); |
100 |
|
} |
101 |
|
|
102 |
|
static struct vgz * |
103 |
8040 |
VGZ_NewGunzip(struct vsl_log *vsl, const char *id) |
104 |
|
{ |
105 |
8040 |
VSC_C_main->n_gunzip++; |
106 |
8040 |
return (vgz_gunzip(vsl, id)); |
107 |
|
} |
108 |
|
|
109 |
|
static struct vgz * |
110 |
1200 |
VGZ_NewTestGunzip(struct vsl_log *vsl, const char *id) |
111 |
|
{ |
112 |
1200 |
VSC_C_main->n_test_gunzip++; |
113 |
1200 |
return (vgz_gunzip(vsl, id)); |
114 |
|
} |
115 |
|
|
116 |
|
struct vgz * |
117 |
3680 |
VGZ_NewGzip(struct vsl_log *vsl, const char *id) |
118 |
|
{ |
119 |
|
struct vgz *vg; |
120 |
|
int i; |
121 |
|
|
122 |
3680 |
VSC_C_main->n_gzip++; |
123 |
3680 |
ALLOC_OBJ(vg, VGZ_MAGIC); |
124 |
3680 |
AN(vg); |
125 |
3680 |
vg->vsl = vsl; |
126 |
3680 |
vg->id = id; |
127 |
3680 |
vg->dir = VGZ_GZ; |
128 |
|
|
129 |
|
/* |
130 |
|
* From zconf.h: |
131 |
|
* |
132 |
|
* mem_needed = "a few kb" |
133 |
|
* + (1 << (windowBits+2)) |
134 |
|
* + (1 << (memLevel+9)) |
135 |
|
* |
136 |
|
* windowBits [8..15] (-> 1K..128K) |
137 |
|
* memLevel [1..9] (-> 1K->256K) |
138 |
|
*/ |
139 |
3680 |
i = deflateInit2(&vg->vz, |
140 |
|
cache_param->gzip_level, /* Level */ |
141 |
|
Z_DEFLATED, /* Method */ |
142 |
|
16 + 15, /* Window bits (16=gzip) */ |
143 |
|
cache_param->gzip_memlevel, /* memLevel */ |
144 |
|
Z_DEFAULT_STRATEGY); |
145 |
3680 |
assert(Z_OK == i); |
146 |
3680 |
return (vg); |
147 |
|
} |
148 |
|
|
149 |
|
/*-------------------------------------------------------------------- |
150 |
|
*/ |
151 |
|
|
152 |
|
static int |
153 |
9880 |
vgz_getmbuf(struct vgz *vg) |
154 |
|
{ |
155 |
|
|
156 |
9880 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
157 |
9880 |
AZ(vg->m_sz); |
158 |
9880 |
AZ(vg->m_len); |
159 |
9880 |
AZ(vg->m_buf); |
160 |
|
|
161 |
9880 |
vg->m_sz = cache_param->gzip_buffer; |
162 |
9880 |
vg->m_buf = malloc(vg->m_sz); |
163 |
9880 |
if (vg->m_buf == NULL) { |
164 |
0 |
vg->m_sz = 0; |
165 |
0 |
return (-1); |
166 |
|
} |
167 |
9880 |
return (0); |
168 |
9880 |
} |
169 |
|
|
170 |
|
/*--------------------------------------------------------------------*/ |
171 |
|
|
172 |
|
void |
173 |
66998 |
VGZ_Ibuf(struct vgz *vg, const void *ptr, ssize_t len) |
174 |
|
{ |
175 |
|
|
176 |
66998 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
177 |
|
|
178 |
66998 |
AZ(vg->vz.avail_in); |
179 |
66998 |
vg->vz.next_in = TRUST_ME(ptr); |
180 |
66998 |
vg->vz.avail_in = len; |
181 |
66998 |
} |
182 |
|
|
183 |
|
int |
184 |
150818 |
VGZ_IbufEmpty(const struct vgz *vg) |
185 |
|
{ |
186 |
|
|
187 |
150818 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
188 |
150818 |
return (vg->vz.avail_in == 0); |
189 |
|
} |
190 |
|
|
191 |
|
/*--------------------------------------------------------------------*/ |
192 |
|
|
193 |
|
void |
194 |
71035 |
VGZ_Obuf(struct vgz *vg, void *ptr, ssize_t len) |
195 |
|
{ |
196 |
|
|
197 |
71035 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
198 |
|
|
199 |
71035 |
vg->vz.next_out = TRUST_ME(ptr); |
200 |
71035 |
vg->vz.avail_out = len; |
201 |
71035 |
} |
202 |
|
|
203 |
|
int |
204 |
42790 |
VGZ_ObufFull(const struct vgz *vg) |
205 |
|
{ |
206 |
|
|
207 |
42790 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
208 |
42790 |
return (vg->vz.avail_out == 0); |
209 |
|
} |
210 |
|
|
211 |
|
/*--------------------------------------------------------------------*/ |
212 |
|
|
213 |
|
static enum vgzret_e |
214 |
32724 |
VGZ_Gunzip(struct vgz *vg, const void **pptr, ssize_t *plen) |
215 |
|
{ |
216 |
|
int i; |
217 |
|
ssize_t l; |
218 |
|
const uint8_t *before; |
219 |
|
|
220 |
32724 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
221 |
|
|
222 |
32724 |
*pptr = NULL; |
223 |
32724 |
*plen = 0; |
224 |
32724 |
AN(vg->vz.next_out); |
225 |
32724 |
AN(vg->vz.avail_out); |
226 |
32724 |
before = vg->vz.next_out; |
227 |
32724 |
i = inflate(&vg->vz, 0); |
228 |
32724 |
if (i == Z_OK || i == Z_STREAM_END) { |
229 |
32563 |
*pptr = before; |
230 |
32563 |
l = (const uint8_t *)vg->vz.next_out - before; |
231 |
32563 |
*plen = l; |
232 |
32563 |
} |
233 |
32724 |
vg->last_i = i; |
234 |
32724 |
if (i == Z_OK) |
235 |
22644 |
return (VGZ_OK); |
236 |
10080 |
if (i == Z_STREAM_END) |
237 |
9920 |
return (VGZ_END); |
238 |
160 |
if (i == Z_BUF_ERROR) |
239 |
80 |
return (VGZ_STUCK); |
240 |
80 |
VSLb(vg->vsl, SLT_Gzip, "Gunzip error: %d (%s)", i, vgz_msg(vg)); |
241 |
80 |
return (VGZ_ERROR); |
242 |
32724 |
} |
243 |
|
|
244 |
|
/*--------------------------------------------------------------------*/ |
245 |
|
|
246 |
|
enum vgzret_e |
247 |
45470 |
VGZ_Gzip(struct vgz *vg, const void **pptr, ssize_t *plen, enum vgz_flag flags) |
248 |
|
{ |
249 |
|
int i; |
250 |
|
int zflg; |
251 |
|
ssize_t l; |
252 |
|
const uint8_t *before; |
253 |
|
|
254 |
45470 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
255 |
|
|
256 |
45470 |
*pptr = NULL; |
257 |
45470 |
*plen = 0; |
258 |
45470 |
AN(vg->vz.next_out); |
259 |
45470 |
AN(vg->vz.avail_out); |
260 |
45470 |
before = vg->vz.next_out; |
261 |
45470 |
switch (flags) { |
262 |
29950 |
case VGZ_NORMAL: zflg = Z_NO_FLUSH; break; |
263 |
5000 |
case VGZ_ALIGN: zflg = Z_SYNC_FLUSH; break; |
264 |
5040 |
case VGZ_RESET: zflg = Z_FULL_FLUSH; break; |
265 |
5480 |
case VGZ_FINISH: zflg = Z_FINISH; break; |
266 |
0 |
default: WRONG("Invalid VGZ flag"); |
267 |
0 |
} |
268 |
45470 |
i = deflate(&vg->vz, zflg); |
269 |
45470 |
if (i == Z_OK || i == Z_STREAM_END) { |
270 |
45470 |
*pptr = before; |
271 |
45470 |
l = (const uint8_t *)vg->vz.next_out - before; |
272 |
45470 |
*plen = l; |
273 |
45470 |
} |
274 |
45470 |
vg->last_i = i; |
275 |
45470 |
if (i == Z_OK) |
276 |
41990 |
return (VGZ_OK); |
277 |
3480 |
if (i == Z_STREAM_END) |
278 |
3480 |
return (VGZ_END); |
279 |
0 |
if (i == Z_BUF_ERROR) |
280 |
0 |
return (VGZ_STUCK); |
281 |
0 |
VSLb(vg->vsl, SLT_Gzip, "Gzip error: %d (%s)", i, vgz_msg(vg)); |
282 |
0 |
return (VGZ_ERROR); |
283 |
45470 |
} |
284 |
|
|
285 |
|
/*-------------------------------------------------------------------- |
286 |
|
* VDP for gunzip'ing |
287 |
|
*/ |
288 |
|
|
289 |
|
static int v_matchproto_(vdp_init_f) |
290 |
3040 |
vdp_gunzip_init(VRT_CTX, struct vdp_ctx *vdc, void **priv) |
291 |
|
{ |
292 |
|
struct vgz *vg; |
293 |
|
struct boc *boc; |
294 |
|
enum boc_state_e bos; |
295 |
|
const char *p; |
296 |
|
ssize_t dl; |
297 |
|
uint64_t u; |
298 |
|
|
299 |
3040 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
300 |
3040 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
301 |
3040 |
CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC); |
302 |
3040 |
CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC); |
303 |
3040 |
AN(vdc->clen); |
304 |
3040 |
AN(priv); |
305 |
|
|
306 |
3040 |
vg = VGZ_NewGunzip(vdc->vsl, "U D -"); |
307 |
3040 |
AN(vg); |
308 |
3040 |
if (vgz_getmbuf(vg)) { |
309 |
0 |
(void)VGZ_Destroy(&vg); |
310 |
0 |
return (-1); |
311 |
|
} |
312 |
|
|
313 |
3040 |
VGZ_Obuf(vg, vg->m_buf, vg->m_sz); |
314 |
3040 |
*priv = vg; |
315 |
|
|
316 |
3040 |
http_Unset(vdc->hp, H_Content_Encoding); |
317 |
|
|
318 |
3040 |
*vdc->clen = -1; |
319 |
|
|
320 |
3040 |
if (vdc->oc == NULL) |
321 |
680 |
return (0); |
322 |
|
|
323 |
2360 |
boc = HSH_RefBoc(vdc->oc); |
324 |
2360 |
if (boc != NULL) { |
325 |
440 |
CHECK_OBJ(boc, BOC_MAGIC); |
326 |
440 |
bos = boc->state; |
327 |
440 |
HSH_DerefBoc(vdc->wrk, vdc->oc); |
328 |
440 |
if (bos < BOS_FINISHED) |
329 |
440 |
return (0); /* OA_GZIPBITS is not stable yet */ |
330 |
0 |
} |
331 |
|
|
332 |
1920 |
p = ObjGetAttr(vdc->wrk, vdc->oc, OA_GZIPBITS, &dl); |
333 |
1920 |
if (p != NULL && dl == 32) { |
334 |
1920 |
u = vbe64dec(p + 24); |
335 |
1920 |
if (u != 0) |
336 |
1880 |
*vdc->clen = u; |
337 |
1920 |
} |
338 |
1920 |
return (0); |
339 |
3040 |
} |
340 |
|
|
341 |
|
static int v_matchproto_(vdp_fini_f) |
342 |
3040 |
vdp_gunzip_fini(struct vdp_ctx *vdc, void **priv) |
343 |
|
{ |
344 |
|
struct vgz *vg; |
345 |
|
|
346 |
3040 |
(void)vdc; |
347 |
3040 |
TAKE_OBJ_NOTNULL(vg, priv, VGZ_MAGIC); |
348 |
3040 |
AN(vg->m_buf); |
349 |
3040 |
(void)VGZ_Destroy(&vg); |
350 |
3040 |
return (0); |
351 |
|
} |
352 |
|
|
353 |
|
static int v_matchproto_(vdp_bytes_f) |
354 |
17398 |
vdp_gunzip_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, |
355 |
|
const void *ptr, ssize_t len) |
356 |
|
{ |
357 |
|
enum vgzret_e vr; |
358 |
|
ssize_t dl; |
359 |
|
const void *dp; |
360 |
|
struct worker *wrk; |
361 |
|
struct vgz *vg; |
362 |
|
|
363 |
17398 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
364 |
17398 |
wrk = vdc->wrk; |
365 |
17398 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
366 |
17398 |
(void)act; |
367 |
|
|
368 |
17398 |
CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC); |
369 |
17398 |
AN(vg->m_buf); |
370 |
|
|
371 |
17398 |
if (len == 0) |
372 |
4679 |
return (0); |
373 |
|
|
374 |
12719 |
VGZ_Ibuf(vg, ptr, len); |
375 |
12719 |
do { |
376 |
12719 |
vr = VGZ_Gunzip(vg, &dp, &dl); |
377 |
12719 |
if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) { |
378 |
80 |
VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)", |
379 |
40 |
vr, "junk after VGZ_END"); |
380 |
40 |
return (-1); |
381 |
|
} |
382 |
12679 |
vg->m_len += dl; |
383 |
12679 |
if (vr < VGZ_OK) |
384 |
0 |
return (-1); |
385 |
12679 |
if (vg->m_len == vg->m_sz || vr != VGZ_OK) { |
386 |
5840 |
if (VDP_bytes(vdc, vr == VGZ_END ? VDP_END : VDP_FLUSH, |
387 |
2920 |
vg->m_buf, vg->m_len)) |
388 |
160 |
return (vdc->retval); |
389 |
2760 |
vg->m_len = 0; |
390 |
2760 |
VGZ_Obuf(vg, vg->m_buf, vg->m_sz); |
391 |
2760 |
} |
392 |
12519 |
} while (!VGZ_IbufEmpty(vg)); |
393 |
12519 |
assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END); |
394 |
12519 |
return (0); |
395 |
17398 |
} |
396 |
|
|
397 |
|
const struct vdp VDP_gunzip = { |
398 |
|
.name = "gunzip", |
399 |
|
.init = vdp_gunzip_init, |
400 |
|
.bytes = vdp_gunzip_bytes, |
401 |
|
.fini = vdp_gunzip_fini, |
402 |
|
}; |
403 |
|
|
404 |
|
/*--------------------------------------------------------------------*/ |
405 |
|
|
406 |
|
void |
407 |
50158 |
VGZ_UpdateObj(const struct vfp_ctx *vc, struct vgz *vg, enum vgzret_e e) |
408 |
|
{ |
409 |
|
char *p; |
410 |
|
intmax_t ii; |
411 |
|
|
412 |
50158 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
413 |
50158 |
if (e < VGZ_OK) |
414 |
0 |
return; |
415 |
50158 |
ii = vg->vz.start_bit + vg->vz.last_bit + vg->vz.stop_bit; |
416 |
50158 |
if (e != VGZ_END && ii == vg->bits) |
417 |
36870 |
return; |
418 |
13288 |
vg->bits = ii; |
419 |
13288 |
p = ObjSetAttr(vc->wrk, vc->oc, OA_GZIPBITS, 32, NULL); |
420 |
13288 |
AN(p); |
421 |
13288 |
vbe64enc(p, vg->vz.start_bit); |
422 |
13288 |
vbe64enc(p + 8, vg->vz.last_bit); |
423 |
13288 |
vbe64enc(p + 16, vg->vz.stop_bit); |
424 |
13288 |
if (e != VGZ_END) |
425 |
5088 |
return; |
426 |
8200 |
if (vg->dir == VGZ_GZ) |
427 |
6960 |
vbe64enc(p + 24, vg->vz.total_in); |
428 |
8200 |
if (vg->dir == VGZ_UN) |
429 |
1240 |
vbe64enc(p + 24, vg->vz.total_out); |
430 |
50158 |
} |
431 |
|
|
432 |
|
/*-------------------------------------------------------------------- |
433 |
|
*/ |
434 |
|
|
435 |
|
enum vgzret_e |
436 |
12920 |
VGZ_Destroy(struct vgz **vgp) |
437 |
|
{ |
438 |
|
struct vgz *vg; |
439 |
|
enum vgzret_e vr; |
440 |
|
int i; |
441 |
|
|
442 |
12920 |
TAKE_OBJ_NOTNULL(vg, vgp, VGZ_MAGIC); |
443 |
12920 |
AN(vg->id); |
444 |
25840 |
VSLb(vg->vsl, SLT_Gzip, "%s %jd %jd %jd %jd %jd", |
445 |
12920 |
vg->id, |
446 |
12920 |
(intmax_t)vg->vz.total_in, |
447 |
12920 |
(intmax_t)vg->vz.total_out, |
448 |
12920 |
(intmax_t)vg->vz.start_bit, |
449 |
12920 |
(intmax_t)vg->vz.last_bit, |
450 |
12920 |
(intmax_t)vg->vz.stop_bit); |
451 |
12920 |
if (vg->dir == VGZ_GZ) |
452 |
3680 |
i = deflateEnd(&vg->vz); |
453 |
|
else |
454 |
9240 |
i = inflateEnd(&vg->vz); |
455 |
12920 |
if (vg->last_i == Z_STREAM_END && i == Z_OK) |
456 |
10320 |
i = Z_STREAM_END; |
457 |
12920 |
if (vg->m_buf) |
458 |
9880 |
free(vg->m_buf); |
459 |
12920 |
if (i == Z_OK) |
460 |
2520 |
vr = VGZ_OK; |
461 |
10400 |
else if (i == Z_STREAM_END) |
462 |
10320 |
vr = VGZ_END; |
463 |
80 |
else if (i == Z_BUF_ERROR) |
464 |
0 |
vr = VGZ_STUCK; |
465 |
|
else { |
466 |
160 |
VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)", |
467 |
80 |
i, vgz_msg(vg)); |
468 |
80 |
vr = VGZ_ERROR; |
469 |
|
} |
470 |
12920 |
FREE_OBJ(vg); |
471 |
12920 |
return (vr); |
472 |
|
} |
473 |
|
|
474 |
|
/*--------------------------------------------------------------------*/ |
475 |
|
|
476 |
|
static enum vfp_status v_matchproto_(vfp_init_f) |
477 |
7000 |
vfp_gzip_init(VRT_CTX, struct vfp_ctx *vc, struct vfp_entry *vfe) |
478 |
|
{ |
479 |
|
struct vgz *vg; |
480 |
|
|
481 |
7000 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
482 |
7000 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
483 |
7000 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
484 |
|
|
485 |
|
/* |
486 |
|
* G(un)zip makes no sence on partial responses, but since |
487 |
|
* it is an pure 1:1 transform, we can just ignore it. |
488 |
|
*/ |
489 |
7000 |
if (http_GetStatus(vc->resp) == 206) |
490 |
160 |
return (VFP_NULL); |
491 |
|
|
492 |
6840 |
if (vfe->vfp == &VFP_gzip) { |
493 |
640 |
if (http_GetHdr(vc->resp, H_Content_Encoding, NULL)) |
494 |
0 |
return (VFP_NULL); |
495 |
640 |
vg = VGZ_NewGzip(vc->wrk->vsl, vfe->vfp->priv1); |
496 |
640 |
vc->obj_flags |= OF_GZIPED | OF_CHGCE; |
497 |
640 |
} else { |
498 |
6200 |
if (!http_HdrIs(vc->resp, H_Content_Encoding, "gzip")) |
499 |
0 |
return (VFP_NULL); |
500 |
6200 |
if (vfe->vfp == &VFP_gunzip) { |
501 |
5000 |
vg = VGZ_NewGunzip(vc->wrk->vsl, vfe->vfp->priv1); |
502 |
5000 |
vc->obj_flags &= ~OF_GZIPED; |
503 |
5000 |
vc->obj_flags |= OF_CHGCE; |
504 |
5000 |
} else { |
505 |
1200 |
vg = VGZ_NewTestGunzip(vc->wrk->vsl, vfe->vfp->priv1); |
506 |
1200 |
vc->obj_flags |= OF_GZIPED; |
507 |
|
} |
508 |
|
} |
509 |
6840 |
AN(vg); |
510 |
6840 |
vfe->priv1 = vg; |
511 |
6840 |
if (vgz_getmbuf(vg)) |
512 |
0 |
return (VFP_ERROR); |
513 |
6840 |
VGZ_Ibuf(vg, vg->m_buf, 0); |
514 |
6840 |
AZ(vg->m_len); |
515 |
|
|
516 |
6840 |
if (vfe->vfp == &VFP_gunzip || vfe->vfp == &VFP_gzip) { |
517 |
5640 |
http_Unset(vc->resp, H_Content_Encoding); |
518 |
5640 |
http_Unset(vc->resp, H_Content_Length); |
519 |
5640 |
RFC2616_Weaken_Etag(vc->resp); |
520 |
5640 |
} |
521 |
|
|
522 |
6840 |
if (vfe->vfp == &VFP_gzip) |
523 |
640 |
http_SetHeader(vc->resp, "Content-Encoding: gzip"); |
524 |
|
|
525 |
6840 |
if (vfe->vfp == &VFP_gzip || vfe->vfp == &VFP_testgunzip) |
526 |
1840 |
RFC2616_Vary_AE(vc->resp); |
527 |
|
|
528 |
6840 |
return (VFP_OK); |
529 |
7000 |
} |
530 |
|
|
531 |
|
/*-------------------------------------------------------------------- |
532 |
|
* VFP_GUNZIP |
533 |
|
* |
534 |
|
* A VFP for gunzip'ing an object as we receive it from the backend |
535 |
|
*/ |
536 |
|
|
537 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
538 |
18437 |
vfp_gunzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
539 |
|
ssize_t *lp) |
540 |
|
{ |
541 |
|
ssize_t l; |
542 |
|
struct vgz *vg; |
543 |
18437 |
enum vgzret_e vr = VGZ_ERROR; |
544 |
|
const void *dp; |
545 |
|
ssize_t dl; |
546 |
18437 |
enum vfp_status vp = VFP_OK; |
547 |
|
|
548 |
18437 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
549 |
18437 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
550 |
18437 |
CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); |
551 |
18437 |
AN(p); |
552 |
18437 |
AN(lp); |
553 |
18437 |
l = *lp; |
554 |
18437 |
*lp = 0; |
555 |
18437 |
VGZ_Obuf(vg, p, l); |
556 |
18437 |
do { |
557 |
18517 |
if (VGZ_IbufEmpty(vg)) { |
558 |
5800 |
l = vg->m_sz; |
559 |
5800 |
vp = VFP_Suck(vc, vg->m_buf, &l); |
560 |
5800 |
if (vp == VFP_ERROR) |
561 |
0 |
return (vp); |
562 |
5800 |
VGZ_Ibuf(vg, vg->m_buf, l); |
563 |
5800 |
} |
564 |
18517 |
if (!VGZ_IbufEmpty(vg) || vp == VFP_END) { |
565 |
18517 |
vr = VGZ_Gunzip(vg, &dp, &dl); |
566 |
18517 |
if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) |
567 |
40 |
return (VFP_Error(vc, "Junk after gzip data")); |
568 |
18477 |
if (vr < VGZ_OK) |
569 |
160 |
return (VFP_Error(vc, |
570 |
80 |
"Invalid Gzip data: %s", vgz_msg(vg))); |
571 |
18397 |
if (dl > 0) { |
572 |
15517 |
*lp = dl; |
573 |
15517 |
assert(dp == p); |
574 |
15517 |
return (VFP_OK); |
575 |
|
} |
576 |
2880 |
} |
577 |
2880 |
AN(VGZ_IbufEmpty(vg)); |
578 |
2880 |
} while (vp == VFP_OK); |
579 |
2800 |
if (vr != VGZ_END) |
580 |
40 |
return (VFP_Error(vc, "Gunzip error at the very end")); |
581 |
2760 |
return (vp); |
582 |
18437 |
} |
583 |
|
|
584 |
|
|
585 |
|
/*-------------------------------------------------------------------- |
586 |
|
* VFP_GZIP |
587 |
|
* |
588 |
|
* A VFP for gzip'ing an object as we receive it from the backend |
589 |
|
*/ |
590 |
|
|
591 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
592 |
2520 |
vfp_gzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
593 |
|
ssize_t *lp) |
594 |
|
{ |
595 |
|
ssize_t l; |
596 |
|
struct vgz *vg; |
597 |
2520 |
enum vgzret_e vr = VGZ_ERROR; |
598 |
|
const void *dp; |
599 |
|
ssize_t dl; |
600 |
2520 |
enum vfp_status vp = VFP_ERROR; |
601 |
|
|
602 |
2520 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
603 |
2520 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
604 |
2520 |
CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); |
605 |
2520 |
AN(p); |
606 |
2520 |
AN(lp); |
607 |
2520 |
l = *lp; |
608 |
2520 |
*lp = 0; |
609 |
2520 |
VGZ_Obuf(vg, p, l); |
610 |
2520 |
do { |
611 |
2680 |
if (VGZ_IbufEmpty(vg)) { |
612 |
2520 |
l = vg->m_sz; |
613 |
2520 |
vp = VFP_Suck(vc, vg->m_buf, &l); |
614 |
2520 |
if (vp == VFP_ERROR) |
615 |
0 |
break; |
616 |
2520 |
if (vp == VFP_END) |
617 |
880 |
vg->flag = VGZ_FINISH; |
618 |
2520 |
VGZ_Ibuf(vg, vg->m_buf, l); |
619 |
2520 |
} |
620 |
2680 |
if (!VGZ_IbufEmpty(vg) || vg->flag == VGZ_FINISH) { |
621 |
2680 |
vr = VGZ_Gzip(vg, &dp, &dl, vg->flag); |
622 |
2680 |
if (vr < VGZ_OK) |
623 |
0 |
return (VFP_Error(vc, "Gzip failed")); |
624 |
2680 |
if (dl > 0) { |
625 |
2520 |
VGZ_UpdateObj(vc, vg, vr); |
626 |
2520 |
*lp = dl; |
627 |
2520 |
assert(dp == p); |
628 |
2520 |
if (vr != VGZ_END || !VGZ_IbufEmpty(vg)) |
629 |
1920 |
return (VFP_OK); |
630 |
600 |
} |
631 |
760 |
} |
632 |
760 |
AN(VGZ_IbufEmpty(vg)); |
633 |
760 |
} while (vg->flag != VGZ_FINISH); |
634 |
|
|
635 |
600 |
if (vr != VGZ_END) |
636 |
0 |
return (VFP_Error(vc, "Gzip failed")); |
637 |
600 |
VGZ_UpdateObj(vc, vg, VGZ_END); |
638 |
600 |
return (VFP_END); |
639 |
2520 |
} |
640 |
|
|
641 |
|
/*-------------------------------------------------------------------- |
642 |
|
* VFP_TESTGZIP |
643 |
|
* |
644 |
|
* A VFP for testing that received gzip data is valid, and for |
645 |
|
* collecting the magic bits while we're at it. |
646 |
|
*/ |
647 |
|
|
648 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
649 |
1568 |
vfp_testgunzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
650 |
|
ssize_t *lp) |
651 |
|
{ |
652 |
|
struct vgz *vg; |
653 |
1568 |
enum vgzret_e vr = VGZ_ERROR; |
654 |
|
const void *dp; |
655 |
|
ssize_t dl; |
656 |
|
enum vfp_status vp; |
657 |
|
|
658 |
1568 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
659 |
1568 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
660 |
1568 |
CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); |
661 |
1568 |
AN(p); |
662 |
1568 |
AN(lp); |
663 |
1568 |
vp = VFP_Suck(vc, p, lp); |
664 |
1568 |
if (vp == VFP_ERROR) |
665 |
80 |
return (vp); |
666 |
1488 |
if (*lp > 0 || vp == VFP_END) { |
667 |
1488 |
VGZ_Ibuf(vg, p, *lp); |
668 |
1488 |
do { |
669 |
1488 |
VGZ_Obuf(vg, vg->m_buf, vg->m_sz); |
670 |
1488 |
vr = VGZ_Gunzip(vg, &dp, &dl); |
671 |
1488 |
if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) |
672 |
120 |
return (VFP_Error(vc, "Junk after gzip data")); |
673 |
1368 |
if (vr < VGZ_OK) |
674 |
0 |
return (VFP_Error(vc, |
675 |
0 |
"Invalid Gzip data: %s", vgz_msg(vg))); |
676 |
1368 |
} while (!VGZ_IbufEmpty(vg)); |
677 |
1368 |
} |
678 |
1368 |
VGZ_UpdateObj(vc, vg, vr); |
679 |
1368 |
if (vp == VFP_END && vr != VGZ_END) |
680 |
40 |
return (VFP_Error(vc, "tGunzip failed")); |
681 |
1328 |
return (vp); |
682 |
1568 |
} |
683 |
|
|
684 |
|
/*--------------------------------------------------------------------*/ |
685 |
|
|
686 |
|
static void v_matchproto_(vfp_fini_f) |
687 |
7440 |
vfp_gzip_fini(struct vfp_ctx *vc, struct vfp_entry *vfe) |
688 |
|
{ |
689 |
|
struct vgz *vg; |
690 |
|
|
691 |
7440 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
692 |
7440 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
693 |
|
|
694 |
7440 |
if (vfe->priv1 != NULL) { |
695 |
6840 |
TAKE_OBJ_NOTNULL(vg, &vfe->priv1, VGZ_MAGIC); |
696 |
6840 |
(void)VGZ_Destroy(&vg); |
697 |
6840 |
} |
698 |
7440 |
} |
699 |
|
|
700 |
|
/*--------------------------------------------------------------------*/ |
701 |
|
|
702 |
|
const struct vfp VFP_gunzip = { |
703 |
|
.name = "gunzip", |
704 |
|
.init = vfp_gzip_init, |
705 |
|
.pull = vfp_gunzip_pull, |
706 |
|
.fini = vfp_gzip_fini, |
707 |
|
.priv1 = "U F -", |
708 |
|
}; |
709 |
|
|
710 |
|
const struct vfp VFP_gzip = { |
711 |
|
.name = "gzip", |
712 |
|
.init = vfp_gzip_init, |
713 |
|
.pull = vfp_gzip_pull, |
714 |
|
.fini = vfp_gzip_fini, |
715 |
|
.priv1 = "G F -", |
716 |
|
}; |
717 |
|
|
718 |
|
const struct vfp VFP_testgunzip = { |
719 |
|
.name = "testgunzip", |
720 |
|
.init = vfp_gzip_init, |
721 |
|
.pull = vfp_testgunzip_pull, |
722 |
|
.fini = vfp_gzip_fini, |
723 |
|
.priv1 = "u F -", |
724 |
|
}; |