| | 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 linvgz (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 |
150 |
vgz_msg(const struct vgz *vg) |
72 |
|
{ |
73 |
150 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
74 |
150 |
return (vg->vz.msg ? vg->vz.msg : "(null)"); |
75 |
|
} |
76 |
|
|
77 |
|
/*-------------------------------------------------------------------- |
78 |
|
* Set up a gunzip instance |
79 |
|
*/ |
80 |
|
|
81 |
|
static struct vgz * |
82 |
5775 |
vgz_gunzip(struct vsl_log *vsl, const char *id) |
83 |
|
{ |
84 |
|
struct vgz *vg; |
85 |
|
|
86 |
5775 |
ALLOC_OBJ(vg, VGZ_MAGIC); |
87 |
5775 |
AN(vg); |
88 |
5775 |
vg->vsl = vsl; |
89 |
5775 |
vg->id = id; |
90 |
5775 |
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 |
5775 |
assert(Z_OK == inflateInit2(&vg->vz, 31)); |
99 |
5775 |
return (vg); |
100 |
|
} |
101 |
|
|
102 |
|
static struct vgz * |
103 |
5025 |
VGZ_NewGunzip(struct vsl_log *vsl, const char *id) |
104 |
|
{ |
105 |
5025 |
VSC_C_main->n_gunzip++; |
106 |
5025 |
return (vgz_gunzip(vsl, id)); |
107 |
|
} |
108 |
|
|
109 |
|
static struct vgz * |
110 |
750 |
VGZ_NewTestGunzip(struct vsl_log *vsl, const char *id) |
111 |
|
{ |
112 |
750 |
VSC_C_main->n_test_gunzip++; |
113 |
750 |
return (vgz_gunzip(vsl, id)); |
114 |
|
} |
115 |
|
|
116 |
|
struct vgz * |
117 |
2300 |
VGZ_NewGzip(struct vsl_log *vsl, const char *id) |
118 |
|
{ |
119 |
|
struct vgz *vg; |
120 |
|
int i; |
121 |
|
|
122 |
2300 |
VSC_C_main->n_gzip++; |
123 |
2300 |
ALLOC_OBJ(vg, VGZ_MAGIC); |
124 |
2300 |
AN(vg); |
125 |
2300 |
vg->vsl = vsl; |
126 |
2300 |
vg->id = id; |
127 |
2300 |
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 |
2300 |
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 |
2300 |
assert(Z_OK == i); |
146 |
2300 |
return (vg); |
147 |
|
} |
148 |
|
|
149 |
|
/*-------------------------------------------------------------------- |
150 |
|
*/ |
151 |
|
|
152 |
|
static int |
153 |
6175 |
vgz_getmbuf(struct vgz *vg) |
154 |
|
{ |
155 |
|
|
156 |
6175 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
157 |
6175 |
AZ(vg->m_sz); |
158 |
6175 |
AZ(vg->m_len); |
159 |
6175 |
AZ(vg->m_buf); |
160 |
|
|
161 |
6175 |
vg->m_sz = cache_param->gzip_buffer; |
162 |
6175 |
vg->m_buf = malloc(vg->m_sz); |
163 |
6175 |
if (vg->m_buf == NULL) { |
164 |
0 |
vg->m_sz = 0; |
165 |
0 |
return (-1); |
166 |
|
} |
167 |
6175 |
return (0); |
168 |
6175 |
} |
169 |
|
|
170 |
|
/*--------------------------------------------------------------------*/ |
171 |
|
|
172 |
|
void |
173 |
41915 |
VGZ_Ibuf(struct vgz *vg, const void *ptr, ssize_t len) |
174 |
|
{ |
175 |
|
|
176 |
41915 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
177 |
|
|
178 |
41915 |
AZ(vg->vz.avail_in); |
179 |
41915 |
vg->vz.next_in = TRUST_ME(ptr); |
180 |
41915 |
vg->vz.avail_in = len; |
181 |
41915 |
} |
182 |
|
|
183 |
|
int |
184 |
94287 |
VGZ_IbufEmpty(const struct vgz *vg) |
185 |
|
{ |
186 |
|
|
187 |
94287 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
188 |
94287 |
return (vg->vz.avail_in == 0); |
189 |
|
} |
190 |
|
|
191 |
|
/*--------------------------------------------------------------------*/ |
192 |
|
|
193 |
|
void |
194 |
44409 |
VGZ_Obuf(struct vgz *vg, void *ptr, ssize_t len) |
195 |
|
{ |
196 |
|
|
197 |
44409 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
198 |
|
|
199 |
44409 |
vg->vz.next_out = TRUST_ME(ptr); |
200 |
44409 |
vg->vz.avail_out = len; |
201 |
44409 |
} |
202 |
|
|
203 |
|
int |
204 |
26786 |
VGZ_ObufFull(const struct vgz *vg) |
205 |
|
{ |
206 |
|
|
207 |
26786 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
208 |
26786 |
return (vg->vz.avail_out == 0); |
209 |
|
} |
210 |
|
|
211 |
|
/*--------------------------------------------------------------------*/ |
212 |
|
|
213 |
|
static enum vgzret_e |
214 |
20423 |
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 |
20423 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
221 |
|
|
222 |
20423 |
*pptr = NULL; |
223 |
20423 |
*plen = 0; |
224 |
20423 |
AN(vg->vz.next_out); |
225 |
20423 |
AN(vg->vz.avail_out); |
226 |
20423 |
before = vg->vz.next_out; |
227 |
20423 |
i = inflate(&vg->vz, 0); |
228 |
20423 |
if (i == Z_OK || i == Z_STREAM_END) { |
229 |
20323 |
*pptr = before; |
230 |
20323 |
l = (const uint8_t *)vg->vz.next_out - before; |
231 |
20323 |
*plen = l; |
232 |
20323 |
} |
233 |
20423 |
vg->last_i = i; |
234 |
20423 |
if (i == Z_OK) |
235 |
14123 |
return (VGZ_OK); |
236 |
6300 |
if (i == Z_STREAM_END) |
237 |
6200 |
return (VGZ_END); |
238 |
100 |
if (i == Z_BUF_ERROR) |
239 |
50 |
return (VGZ_STUCK); |
240 |
50 |
VSLb(vg->vsl, SLT_Gzip, "Gunzip error: %d (%s)", i, vgz_msg(vg)); |
241 |
50 |
return (VGZ_ERROR); |
242 |
20423 |
} |
243 |
|
|
244 |
|
/*--------------------------------------------------------------------*/ |
245 |
|
|
246 |
|
enum vgzret_e |
247 |
28461 |
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 |
28461 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
255 |
|
|
256 |
28461 |
*pptr = NULL; |
257 |
28461 |
*plen = 0; |
258 |
28461 |
AN(vg->vz.next_out); |
259 |
28461 |
AN(vg->vz.avail_out); |
260 |
28461 |
before = vg->vz.next_out; |
261 |
28461 |
switch (flags) { |
262 |
18761 |
case VGZ_NORMAL: zflg = Z_NO_FLUSH; break; |
263 |
3125 |
case VGZ_ALIGN: zflg = Z_SYNC_FLUSH; break; |
264 |
3150 |
case VGZ_RESET: zflg = Z_FULL_FLUSH; break; |
265 |
3425 |
case VGZ_FINISH: zflg = Z_FINISH; break; |
266 |
0 |
default: INCOMPL(); |
267 |
0 |
} |
268 |
28461 |
i = deflate(&vg->vz, zflg); |
269 |
28461 |
if (i == Z_OK || i == Z_STREAM_END) { |
270 |
28461 |
*pptr = before; |
271 |
28461 |
l = (const uint8_t *)vg->vz.next_out - before; |
272 |
28461 |
*plen = l; |
273 |
28461 |
} |
274 |
28461 |
vg->last_i = i; |
275 |
28461 |
if (i == Z_OK) |
276 |
26286 |
return (VGZ_OK); |
277 |
2175 |
if (i == Z_STREAM_END) |
278 |
2175 |
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 |
28461 |
} |
284 |
|
|
285 |
|
/*-------------------------------------------------------------------- |
286 |
|
* VDP for gunzip'ing |
287 |
|
*/ |
288 |
|
|
289 |
|
static int v_matchproto_(vdp_init_f) |
290 |
1900 |
vdp_gunzip_init(VRT_CTX, struct vdp_ctx *vdc, void **priv, struct objcore *oc) |
291 |
|
{ |
292 |
|
struct vgz *vg; |
293 |
|
struct boc *boc; |
294 |
|
struct req *req; |
295 |
|
enum boc_state_e bos; |
296 |
|
const char *p; |
297 |
|
ssize_t dl; |
298 |
|
uint64_t u; |
299 |
|
|
300 |
1900 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
301 |
1900 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
302 |
1900 |
CHECK_OBJ_ORNULL(oc, OBJCORE_MAGIC); |
303 |
1900 |
req = vdc->req; |
304 |
1900 |
CHECK_OBJ_NOTNULL(req, REQ_MAGIC); |
305 |
|
|
306 |
1900 |
vg = VGZ_NewGunzip(vdc->vsl, "U D -"); |
307 |
1900 |
AN(vg); |
308 |
1900 |
if (vgz_getmbuf(vg)) { |
309 |
0 |
(void)VGZ_Destroy(&vg); |
310 |
0 |
return (-1); |
311 |
|
} |
312 |
|
|
313 |
1900 |
VGZ_Obuf(vg, vg->m_buf, vg->m_sz); |
314 |
1900 |
*priv = vg; |
315 |
|
|
316 |
1900 |
http_Unset(req->resp, H_Content_Encoding); |
317 |
|
|
318 |
1900 |
req->resp_len = -1; |
319 |
|
|
320 |
1900 |
if (oc == NULL) |
321 |
425 |
return (0); |
322 |
|
|
323 |
1475 |
boc = HSH_RefBoc(oc); |
324 |
1475 |
if (boc != NULL) { |
325 |
275 |
CHECK_OBJ(boc, BOC_MAGIC); |
326 |
275 |
bos = boc->state; |
327 |
275 |
HSH_DerefBoc(vdc->wrk, oc); |
328 |
275 |
if (bos < BOS_FINISHED) |
329 |
275 |
return (0); /* OA_GZIPBITS is not stable yet */ |
330 |
0 |
} |
331 |
|
|
332 |
1200 |
p = ObjGetAttr(vdc->wrk, oc, OA_GZIPBITS, &dl); |
333 |
1200 |
if (p != NULL && dl == 32) { |
334 |
1200 |
u = vbe64dec(p + 24); |
335 |
1200 |
if (u != 0) |
336 |
1175 |
req->resp_len = u; |
337 |
1200 |
} |
338 |
1200 |
return (0); |
339 |
1900 |
} |
340 |
|
|
341 |
|
static int v_matchproto_(vdp_fini_f) |
342 |
1900 |
vdp_gunzip_fini(struct vdp_ctx *vdc, void **priv) |
343 |
|
{ |
344 |
|
struct vgz *vg; |
345 |
|
|
346 |
1900 |
(void)vdc; |
347 |
1900 |
CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC); |
348 |
1900 |
AN(vg->m_buf); |
349 |
1900 |
(void)VGZ_Destroy(&vg); |
350 |
1900 |
*priv = NULL; |
351 |
1900 |
return (0); |
352 |
|
} |
353 |
|
|
354 |
|
static int v_matchproto_(vdp_bytes_f) |
355 |
10875 |
vdp_gunzip_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, |
356 |
|
const void *ptr, ssize_t len) |
357 |
|
{ |
358 |
|
enum vgzret_e vr; |
359 |
|
ssize_t dl; |
360 |
|
const void *dp; |
361 |
|
struct worker *wrk; |
362 |
|
struct vgz *vg; |
363 |
|
|
364 |
10875 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
365 |
10875 |
wrk = vdc->wrk; |
366 |
10875 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
367 |
10875 |
(void)act; |
368 |
|
|
369 |
10875 |
CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC); |
370 |
10875 |
AN(vg->m_buf); |
371 |
|
|
372 |
10875 |
if (len == 0) |
373 |
2925 |
return (0); |
374 |
|
|
375 |
7950 |
VGZ_Ibuf(vg, ptr, len); |
376 |
7950 |
do { |
377 |
7950 |
vr = VGZ_Gunzip(vg, &dp, &dl); |
378 |
7950 |
if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) { |
379 |
50 |
VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)", |
380 |
25 |
vr, "junk after VGZ_END"); |
381 |
25 |
return (-1); |
382 |
|
} |
383 |
7925 |
vg->m_len += dl; |
384 |
7925 |
if (vr < VGZ_OK) |
385 |
0 |
return (-1); |
386 |
7925 |
if (vg->m_len == vg->m_sz || vr != VGZ_OK) { |
387 |
3650 |
if (VDP_bytes(vdc, vr == VGZ_END ? VDP_END : VDP_FLUSH, |
388 |
1825 |
vg->m_buf, vg->m_len)) |
389 |
100 |
return (vdc->retval); |
390 |
1725 |
vg->m_len = 0; |
391 |
1725 |
VGZ_Obuf(vg, vg->m_buf, vg->m_sz); |
392 |
1725 |
} |
393 |
7825 |
} while (!VGZ_IbufEmpty(vg)); |
394 |
7825 |
assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END); |
395 |
7825 |
return (0); |
396 |
10875 |
} |
397 |
|
|
398 |
|
const struct vdp VDP_gunzip = { |
399 |
|
.name = "gunzip", |
400 |
|
.init = vdp_gunzip_init, |
401 |
|
.bytes = vdp_gunzip_bytes, |
402 |
|
.fini = vdp_gunzip_fini, |
403 |
|
}; |
404 |
|
|
405 |
|
/*--------------------------------------------------------------------*/ |
406 |
|
|
407 |
|
void |
408 |
31990 |
VGZ_UpdateObj(const struct vfp_ctx *vc, struct vgz *vg, enum vgz_ua_e e) |
409 |
|
{ |
410 |
|
char *p; |
411 |
|
intmax_t ii; |
412 |
|
|
413 |
31990 |
CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); |
414 |
31990 |
ii = vg->vz.start_bit + vg->vz.last_bit + vg->vz.stop_bit; |
415 |
31990 |
if (e == VUA_UPDATE && ii == vg->bits) |
416 |
24361 |
return; |
417 |
7629 |
vg->bits = ii; |
418 |
7629 |
p = ObjSetAttr(vc->wrk, vc->oc, OA_GZIPBITS, 32, NULL); |
419 |
7629 |
AN(p); |
420 |
7629 |
vbe64enc(p, vg->vz.start_bit); |
421 |
7629 |
vbe64enc(p + 8, vg->vz.last_bit); |
422 |
7629 |
vbe64enc(p + 16, vg->vz.stop_bit); |
423 |
7629 |
if (e == VUA_END_GZIP) |
424 |
2175 |
vbe64enc(p + 24, vg->vz.total_in); |
425 |
7629 |
if (e == VUA_END_GUNZIP) |
426 |
600 |
vbe64enc(p + 24, vg->vz.total_out); |
427 |
31990 |
} |
428 |
|
|
429 |
|
/*-------------------------------------------------------------------- |
430 |
|
*/ |
431 |
|
|
432 |
|
enum vgzret_e |
433 |
8075 |
VGZ_Destroy(struct vgz **vgp) |
434 |
|
{ |
435 |
|
struct vgz *vg; |
436 |
|
enum vgzret_e vr; |
437 |
|
int i; |
438 |
|
|
439 |
8075 |
TAKE_OBJ_NOTNULL(vg, vgp, VGZ_MAGIC); |
440 |
8075 |
AN(vg->id); |
441 |
16150 |
VSLb(vg->vsl, SLT_Gzip, "%s %jd %jd %jd %jd %jd", |
442 |
8075 |
vg->id, |
443 |
8075 |
(intmax_t)vg->vz.total_in, |
444 |
8075 |
(intmax_t)vg->vz.total_out, |
445 |
8075 |
(intmax_t)vg->vz.start_bit, |
446 |
8075 |
(intmax_t)vg->vz.last_bit, |
447 |
8075 |
(intmax_t)vg->vz.stop_bit); |
448 |
8075 |
if (vg->dir == VGZ_GZ) |
449 |
2300 |
i = deflateEnd(&vg->vz); |
450 |
|
else |
451 |
5775 |
i = inflateEnd(&vg->vz); |
452 |
8075 |
if (vg->last_i == Z_STREAM_END && i == Z_OK) |
453 |
6450 |
i = Z_STREAM_END; |
454 |
8075 |
if (vg->m_buf) |
455 |
6175 |
free(vg->m_buf); |
456 |
8075 |
if (i == Z_OK) |
457 |
1575 |
vr = VGZ_OK; |
458 |
6500 |
else if (i == Z_STREAM_END) |
459 |
6450 |
vr = VGZ_END; |
460 |
50 |
else if (i == Z_BUF_ERROR) |
461 |
0 |
vr = VGZ_STUCK; |
462 |
|
else { |
463 |
100 |
VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)", |
464 |
50 |
i, vgz_msg(vg)); |
465 |
50 |
vr = VGZ_ERROR; |
466 |
|
} |
467 |
8075 |
FREE_OBJ(vg); |
468 |
8075 |
return (vr); |
469 |
|
} |
470 |
|
|
471 |
|
/*--------------------------------------------------------------------*/ |
472 |
|
|
473 |
|
static enum vfp_status v_matchproto_(vfp_init_f) |
474 |
4375 |
vfp_gzip_init(VRT_CTX, struct vfp_ctx *vc, struct vfp_entry *vfe) |
475 |
|
{ |
476 |
|
struct vgz *vg; |
477 |
|
|
478 |
4375 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
479 |
4375 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
480 |
4375 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
481 |
|
|
482 |
|
/* |
483 |
|
* G(un)zip makes no sence on partial responses, but since |
484 |
|
* it is an pure 1:1 transform, we can just ignore it. |
485 |
|
*/ |
486 |
4375 |
if (http_GetStatus(vc->resp) == 206) |
487 |
100 |
return (VFP_NULL); |
488 |
|
|
489 |
4275 |
if (vfe->vfp == &VFP_gzip) { |
490 |
400 |
if (http_GetHdr(vc->resp, H_Content_Encoding, NULL)) |
491 |
0 |
return (VFP_NULL); |
492 |
400 |
vg = VGZ_NewGzip(vc->wrk->vsl, vfe->vfp->priv1); |
493 |
400 |
vc->obj_flags |= OF_GZIPED | OF_CHGCE; |
494 |
400 |
} else { |
495 |
3875 |
if (!http_HdrIs(vc->resp, H_Content_Encoding, "gzip")) |
496 |
0 |
return (VFP_NULL); |
497 |
3875 |
if (vfe->vfp == &VFP_gunzip) { |
498 |
3125 |
vg = VGZ_NewGunzip(vc->wrk->vsl, vfe->vfp->priv1); |
499 |
3125 |
vc->obj_flags &= ~OF_GZIPED; |
500 |
3125 |
vc->obj_flags |= OF_CHGCE; |
501 |
3125 |
} else { |
502 |
750 |
vg = VGZ_NewTestGunzip(vc->wrk->vsl, vfe->vfp->priv1); |
503 |
750 |
vc->obj_flags |= OF_GZIPED; |
504 |
|
} |
505 |
|
} |
506 |
4275 |
AN(vg); |
507 |
4275 |
vfe->priv1 = vg; |
508 |
4275 |
if (vgz_getmbuf(vg)) |
509 |
0 |
return (VFP_ERROR); |
510 |
4275 |
VGZ_Ibuf(vg, vg->m_buf, 0); |
511 |
4275 |
AZ(vg->m_len); |
512 |
|
|
513 |
4275 |
if (vfe->vfp == &VFP_gunzip || vfe->vfp == &VFP_gzip) { |
514 |
3525 |
http_Unset(vc->resp, H_Content_Encoding); |
515 |
3525 |
http_Unset(vc->resp, H_Content_Length); |
516 |
3525 |
RFC2616_Weaken_Etag(vc->resp); |
517 |
3525 |
} |
518 |
|
|
519 |
4275 |
if (vfe->vfp == &VFP_gzip) |
520 |
400 |
http_SetHeader(vc->resp, "Content-Encoding: gzip"); |
521 |
|
|
522 |
4275 |
if (vfe->vfp == &VFP_gzip || vfe->vfp == &VFP_testgunzip) |
523 |
1150 |
RFC2616_Vary_AE(vc->resp); |
524 |
|
|
525 |
4275 |
return (VFP_OK); |
526 |
4375 |
} |
527 |
|
|
528 |
|
/*-------------------------------------------------------------------- |
529 |
|
* VFP_GUNZIP |
530 |
|
* |
531 |
|
* A VFP for gunzip'ing an object as we receive it from the backend |
532 |
|
*/ |
533 |
|
|
534 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
535 |
11494 |
vfp_gunzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
536 |
|
ssize_t *lp) |
537 |
|
{ |
538 |
|
ssize_t l; |
539 |
|
struct vgz *vg; |
540 |
11494 |
enum vgzret_e vr = VGZ_ERROR; |
541 |
|
const void *dp; |
542 |
|
ssize_t dl; |
543 |
11494 |
enum vfp_status vp = VFP_OK; |
544 |
|
|
545 |
11494 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
546 |
11494 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
547 |
11494 |
CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); |
548 |
11494 |
AN(p); |
549 |
11494 |
AN(lp); |
550 |
11494 |
l = *lp; |
551 |
11494 |
*lp = 0; |
552 |
11494 |
VGZ_Obuf(vg, p, l); |
553 |
11494 |
do { |
554 |
11544 |
if (VGZ_IbufEmpty(vg)) { |
555 |
3625 |
l = vg->m_sz; |
556 |
3625 |
vp = VFP_Suck(vc, vg->m_buf, &l); |
557 |
3625 |
if (vp == VFP_ERROR) |
558 |
0 |
return (vp); |
559 |
3625 |
VGZ_Ibuf(vg, vg->m_buf, l); |
560 |
3625 |
} |
561 |
11544 |
if (!VGZ_IbufEmpty(vg) || vp == VFP_END) { |
562 |
11544 |
vr = VGZ_Gunzip(vg, &dp, &dl); |
563 |
11544 |
if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) |
564 |
25 |
return (VFP_Error(vc, "Junk after gzip data")); |
565 |
11519 |
if (vr < VGZ_OK) |
566 |
100 |
return (VFP_Error(vc, |
567 |
50 |
"Invalid Gzip data: %s", vgz_msg(vg))); |
568 |
11469 |
if (dl > 0) { |
569 |
9669 |
*lp = dl; |
570 |
9669 |
assert(dp == p); |
571 |
9669 |
return (VFP_OK); |
572 |
|
} |
573 |
1800 |
} |
574 |
1800 |
AN(VGZ_IbufEmpty(vg)); |
575 |
1800 |
} while (vp == VFP_OK); |
576 |
1750 |
if (vr != VGZ_END) |
577 |
25 |
return (VFP_Error(vc, "Gunzip error at the very end")); |
578 |
1725 |
return (vp); |
579 |
11494 |
} |
580 |
|
|
581 |
|
|
582 |
|
/*-------------------------------------------------------------------- |
583 |
|
* VFP_GZIP |
584 |
|
* |
585 |
|
* A VFP for gzip'ing an object as we receive it from the backend |
586 |
|
*/ |
587 |
|
|
588 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
589 |
1575 |
vfp_gzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
590 |
|
ssize_t *lp) |
591 |
|
{ |
592 |
|
ssize_t l; |
593 |
|
struct vgz *vg; |
594 |
1575 |
enum vgzret_e vr = VGZ_ERROR; |
595 |
|
const void *dp; |
596 |
|
ssize_t dl; |
597 |
1575 |
enum vfp_status vp = VFP_ERROR; |
598 |
|
|
599 |
1575 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
600 |
1575 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
601 |
1575 |
CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); |
602 |
1575 |
AN(p); |
603 |
1575 |
AN(lp); |
604 |
1575 |
l = *lp; |
605 |
1575 |
*lp = 0; |
606 |
1575 |
VGZ_Obuf(vg, p, l); |
607 |
1575 |
do { |
608 |
1675 |
if (VGZ_IbufEmpty(vg)) { |
609 |
1575 |
l = vg->m_sz; |
610 |
1575 |
vp = VFP_Suck(vc, vg->m_buf, &l); |
611 |
1575 |
if (vp == VFP_ERROR) |
612 |
0 |
break; |
613 |
1575 |
if (vp == VFP_END) |
614 |
550 |
vg->flag = VGZ_FINISH; |
615 |
1575 |
VGZ_Ibuf(vg, vg->m_buf, l); |
616 |
1575 |
} |
617 |
1675 |
if (!VGZ_IbufEmpty(vg) || vg->flag == VGZ_FINISH) { |
618 |
1675 |
vr = VGZ_Gzip(vg, &dp, &dl, vg->flag); |
619 |
1675 |
if (vr < VGZ_OK) |
620 |
0 |
return (VFP_Error(vc, "Gzip failed")); |
621 |
1675 |
if (dl > 0) { |
622 |
1575 |
VGZ_UpdateObj(vc, vg, VUA_UPDATE); |
623 |
1575 |
*lp = dl; |
624 |
1575 |
assert(dp == p); |
625 |
1575 |
if (vr != VGZ_END || !VGZ_IbufEmpty(vg)) |
626 |
1200 |
return (VFP_OK); |
627 |
375 |
} |
628 |
475 |
} |
629 |
475 |
AN(VGZ_IbufEmpty(vg)); |
630 |
475 |
} while (vg->flag != VGZ_FINISH); |
631 |
|
|
632 |
375 |
if (vr != VGZ_END) |
633 |
0 |
return (VFP_Error(vc, "Gzip failed")); |
634 |
375 |
VGZ_UpdateObj(vc, vg, VUA_END_GZIP); |
635 |
375 |
return (VFP_END); |
636 |
1575 |
} |
637 |
|
|
638 |
|
/*-------------------------------------------------------------------- |
639 |
|
* VFP_TESTGZIP |
640 |
|
* |
641 |
|
* A VFP for testing that received gzip data is valid, and for |
642 |
|
* collecting the magic bits while we're at it. |
643 |
|
*/ |
644 |
|
|
645 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
646 |
979 |
vfp_testgunzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
647 |
|
ssize_t *lp) |
648 |
|
{ |
649 |
|
struct vgz *vg; |
650 |
979 |
enum vgzret_e vr = VGZ_ERROR; |
651 |
|
const void *dp; |
652 |
|
ssize_t dl; |
653 |
|
enum vfp_status vp; |
654 |
|
|
655 |
979 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
656 |
979 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
657 |
979 |
CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); |
658 |
979 |
AN(p); |
659 |
979 |
AN(lp); |
660 |
979 |
vp = VFP_Suck(vc, p, lp); |
661 |
979 |
if (vp == VFP_ERROR) |
662 |
50 |
return (vp); |
663 |
929 |
if (*lp > 0 || vp == VFP_END) { |
664 |
929 |
VGZ_Ibuf(vg, p, *lp); |
665 |
929 |
do { |
666 |
929 |
VGZ_Obuf(vg, vg->m_buf, vg->m_sz); |
667 |
929 |
vr = VGZ_Gunzip(vg, &dp, &dl); |
668 |
929 |
if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) |
669 |
75 |
return (VFP_Error(vc, "Junk after gzip data")); |
670 |
854 |
if (vr < VGZ_OK) |
671 |
0 |
return (VFP_Error(vc, |
672 |
0 |
"Invalid Gzip data: %s", vgz_msg(vg))); |
673 |
854 |
} while (!VGZ_IbufEmpty(vg)); |
674 |
854 |
} |
675 |
854 |
VGZ_UpdateObj(vc, vg, VUA_UPDATE); |
676 |
854 |
if (vp == VFP_END) { |
677 |
625 |
if (vr != VGZ_END) |
678 |
25 |
return (VFP_Error(vc, "tGunzip failed")); |
679 |
600 |
VGZ_UpdateObj(vc, vg, VUA_END_GUNZIP); |
680 |
600 |
} |
681 |
829 |
return (vp); |
682 |
979 |
} |
683 |
|
|
684 |
|
/*--------------------------------------------------------------------*/ |
685 |
|
|
686 |
|
static void v_matchproto_(vfp_fini_f) |
687 |
4650 |
vfp_gzip_fini(struct vfp_ctx *vc, struct vfp_entry *vfe) |
688 |
|
{ |
689 |
|
struct vgz *vg; |
690 |
|
|
691 |
4650 |
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); |
692 |
4650 |
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); |
693 |
|
|
694 |
4650 |
if (vfe->priv1 != NULL) { |
695 |
4275 |
TAKE_OBJ_NOTNULL(vg, &vfe->priv1, VGZ_MAGIC); |
696 |
4275 |
(void)VGZ_Destroy(&vg); |
697 |
4275 |
} |
698 |
4650 |
} |
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 |
|
}; |