ved_pretend_gzip(struct req *req, enum vdp_action act, void **priv, const void *pv, ssize_t l) { uint8_t buf1[5], buf2[5]; const uint8_t *p; uint16_t lx; struct ecx *ecx; struct req *preq; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CAST_OBJ_NOTNULL(ecx, *priv, ECX_MAGIC); preq = ecx->preq; (void)priv; if (act == VDP_INIT) return (0); if (act == VDP_FINI) { *priv = NULL; return (0); } if (l == 0) return (ved_bytes(req, ecx->preq, act, pv, l)); p = pv; if (ecx->isgzip) { ecx->crc = crc32(ecx->crc, p, l); ecx->l_crc += l; } lx = 65535; buf1[0] = 0; vle16enc(buf1 + 1, lx); vle16enc(buf1 + 3, ~lx); while (l > 0) { if (l >= 65535) { lx = 65535; if (ved_bytes(req, preq, VDP_NULL, buf1, sizeof buf1)) return (-1); } else { lx = (uint16_t)l; buf2[0] = 0; vle16enc(buf2 + 1, lx); vle16enc(buf2 + 3, ~lx); if (ved_bytes(req, preq, VDP_NULL, buf2, sizeof buf2)) return (-1); } if (ved_bytes(req, preq, VDP_NULL, p, lx)) return (-1); l -= lx; p += lx; } /* buf2 is local, have to flush */ return (ved_bytes(req, preq, VDP_FLUSH, NULL, 0)); }
ved_vdp_bytes(struct req *req, enum vdp_action act, void **priv, const void *ptr, ssize_t len) { struct req *preq; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); if (act == VDP_INIT) return (0); if (act == VDP_FINI) { *priv = NULL; return (0); } CAST_OBJ_NOTNULL(preq, *priv, REQ_MAGIC); return (ved_bytes(req, preq, act, ptr, len)); }
static void ved_stripgzip(struct req *req, struct busyobj *bo) { ssize_t start, last, stop, lpad; ssize_t l; char *p; uint32_t icrc; uint32_t ilen; uint64_t olen; uint8_t *dbits; uint8_t *pp; uint8_t tailbuf[8]; enum objiter_status ois; void *oi; void *sp; ssize_t sl, ll, dl; struct ecx *ecx; struct req *preq; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC); preq = ecx->preq; if (bo != NULL) VBO_waitstate(bo, BOS_FINISHED); AN(ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED)); /* * This is the interesting case: Deliver all the deflate * blocks, stripping the "LAST" bit of the last one and * padding it, as necessary, to a byte boundary. */ p = ObjGetattr(req->wrk, req->objcore, OA_GZIPBITS, &l); AN(p); assert(l == 32); start = vbe64dec(p); last = vbe64dec(p + 8); stop = vbe64dec(p + 16); olen = ObjGetLen(req->wrk, req->objcore); assert(start > 0 && start < olen * 8); assert(last > 0 && last < olen * 8); assert(stop > 0 && stop < olen * 8); assert(last >= start); assert(last < stop); /* The start bit must be byte aligned. */ AZ(start & 7); /* * XXX: optimize for the case where the 'last' * XXX: bit is in a empty copy block */ memset(tailbuf, 0xdd, sizeof tailbuf); dbits = WS_Alloc(req->ws, 8); AN(dbits); ll = 0; oi = ObjIterBegin(req->wrk, req->objcore); do { ois = ObjIter(req->objcore, oi, &sp, &sl); pp = sp; if (sl > 0) { /* Skip over the GZIP header */ dl = start / 8 - ll; if (dl > 0) { /* Before start, skip */ if (dl > sl) dl = sl; ll += dl; sl -= dl; pp += dl; } } if (sl > 0) { /* The main body of the object */ dl = last / 8 - ll; if (dl > 0) { if (dl > sl) dl = sl; if (ved_bytes(req, preq, VDP_NULL, pp, dl)) break; ll += dl; sl -= dl; pp += dl; } } if (sl > 0 && ll == last / 8) { /* Remove the "LAST" bit */ dbits[0] = *pp; dbits[0] &= ~(1U << (last & 7)); if (ved_bytes(req, preq, VDP_NULL, dbits, 1)) break; ll++; sl--; pp++; } if (sl > 0) { /* Last block */ dl = stop / 8 - ll; if (dl > 0) { if (dl > sl) dl = sl; if (ved_bytes(req, preq, VDP_NULL, pp, dl)) break; ll += dl; sl -= dl; pp += dl; } } if (sl > 0 && (stop & 7) && ll == stop / 8) { /* Add alignment to byte boundary */ dbits[1] = *pp; ll++; sl--; pp++; switch((int)(stop & 7)) { case 1: /* * x000.... * 00000000 00000000 11111111 11111111 */ case 3: /* * xxx000.. * 00000000 00000000 11111111 11111111 */ case 5: /* * xxxxx000 * 00000000 00000000 11111111 11111111 */ dbits[2] = 0x00; dbits[3] = 0x00; dbits[4] = 0xff; dbits[5] = 0xff; lpad = 5; break; case 2: /* xx010000 00000100 00000001 00000000 */ dbits[1] |= 0x08; dbits[2] = 0x20; dbits[3] = 0x80; dbits[4] = 0x00; lpad = 4; break; case 4: /* xxxx0100 00000001 00000000 */ dbits[1] |= 0x20; dbits[2] = 0x80; dbits[3] = 0x00; lpad = 3; break; case 6: /* xxxxxx01 00000000 */ dbits[1] |= 0x80; dbits[2] = 0x00; lpad = 2; break; case 7: /* * xxxxxxx0 * 00...... * 00000000 00000000 11111111 11111111 */ dbits[2] = 0x00; dbits[3] = 0x00; dbits[4] = 0x00; dbits[5] = 0xff; dbits[6] = 0xff; lpad = 6; break; case 0: /* xxxxxxxx */ default: WRONG("compiler must be broken"); } if (ved_bytes(req, preq, VDP_NULL, dbits + 1, lpad)) break; } if (sl > 0) { /* Recover GZIP tail */ dl = olen - ll; assert(dl >= 0); if (dl > sl) dl = sl; if (dl > 0) { assert(dl <= 8); l = ll - (olen - 8); assert(l >= 0); assert(l <= 8); assert(l + dl <= 8); memcpy(tailbuf + l, pp, dl); ll += dl; sl -= dl; pp += dl; } } } while (ois == OIS_DATA || ois == OIS_STREAM); ObjIterEnd(req->objcore, &oi); (void)ved_bytes(req, preq, VDP_FLUSH, NULL, 0); icrc = vle32dec(tailbuf); ilen = vle32dec(tailbuf + 4); ecx->crc = crc32_combine(ecx->crc, icrc, ilen); ecx->l_crc += ilen; }
static void ved_stripgzip(struct req *req, const struct boc *boc) { ssize_t l; char *p; uint32_t icrc; uint32_t ilen; uint8_t *dbits; struct ecx *ecx; struct ved_foo foo; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC); INIT_OBJ(&foo, VED_FOO_MAGIC); foo.req = req; foo.preq = ecx->preq; memset(foo.tailbuf, 0xdd, sizeof foo.tailbuf); /* OA_GZIPBITS is not valid until BOS_FINISHED */ if (boc != NULL) ObjWaitState(req->objcore, BOS_FINISHED); AN(ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED)); /* * This is the interesting case: Deliver all the deflate * blocks, stripping the "LAST" bit of the last one and * padding it, as necessary, to a byte boundary. */ p = ObjGetAttr(req->wrk, req->objcore, OA_GZIPBITS, &l); AN(p); assert(l == 32); foo.start = vbe64dec(p); foo.last = vbe64dec(p + 8); foo.stop = vbe64dec(p + 16); foo.olen = ObjGetLen(req->wrk, req->objcore); assert(foo.start > 0 && foo.start < foo.olen * 8); assert(foo.last > 0 && foo.last < foo.olen * 8); assert(foo.stop > 0 && foo.stop < foo.olen * 8); assert(foo.last >= foo.start); assert(foo.last < foo.stop); /* The start bit must be byte aligned. */ AZ(foo.start & 7); dbits = WS_Alloc(req->ws, 8); AN(dbits); foo.dbits = dbits; (void)ObjIterate(req->wrk, req->objcore, &foo, ved_objiterate); /* XXX: error check ?? */ (void)ved_bytes(req, foo.preq, VDP_FLUSH, NULL, 0); icrc = vle32dec(foo.tailbuf); ilen = vle32dec(foo.tailbuf + 4); ecx->crc = crc32_combine(ecx->crc, icrc, ilen); ecx->l_crc += ilen; }
static int ved_objiterate(void *priv, int flush, const void *ptr, ssize_t len) { struct ved_foo *foo; const uint8_t *pp; ssize_t dl; ssize_t l; CAST_OBJ_NOTNULL(foo, priv, VED_FOO_MAGIC); (void)flush; pp = ptr; if (len > 0) { /* Skip over the GZIP header */ dl = foo->start / 8 - foo->ll; if (dl > 0) { /* Before foo.start, skip */ if (dl > len) dl = len; foo->ll += dl; len -= dl; pp += dl; } } if (len > 0) { /* The main body of the object */ dl = foo->last / 8 - foo->ll; if (dl > 0) { if (dl > len) dl = len; if (ved_bytes(foo->req, foo->preq, VDP_NULL, pp, dl)) return(-1); foo->ll += dl; len -= dl; pp += dl; } } if (len > 0 && foo->ll == foo->last / 8) { /* Remove the "LAST" bit */ foo->dbits[0] = *pp; foo->dbits[0] &= ~(1U << (foo->last & 7)); if (ved_bytes(foo->req, foo->preq, VDP_NULL, foo->dbits, 1)) return (-1); foo->ll++; len--; pp++; } if (len > 0) { /* Last block */ dl = foo->stop / 8 - foo->ll; if (dl > 0) { if (dl > len) dl = len; if (ved_bytes(foo->req, foo->preq, VDP_NULL, pp, dl)) return (-1); foo->ll += dl; len -= dl; pp += dl; } } if (len > 0 && (foo->stop & 7) && foo->ll == foo->stop / 8) { /* Add alignment to byte boundary */ foo->dbits[1] = *pp; foo->ll++; len--; pp++; switch((int)(foo->stop & 7)) { case 1: /* * x000.... * 00000000 00000000 11111111 11111111 */ case 3: /* * xxx000.. * 00000000 00000000 11111111 11111111 */ case 5: /* * xxxxx000 * 00000000 00000000 11111111 11111111 */ foo->dbits[2] = 0x00; foo->dbits[3] = 0x00; foo->dbits[4] = 0xff; foo->dbits[5] = 0xff; foo->lpad = 5; break; case 2: /* xx010000 00000100 00000001 00000000 */ foo->dbits[1] |= 0x08; foo->dbits[2] = 0x20; foo->dbits[3] = 0x80; foo->dbits[4] = 0x00; foo->lpad = 4; break; case 4: /* xxxx0100 00000001 00000000 */ foo->dbits[1] |= 0x20; foo->dbits[2] = 0x80; foo->dbits[3] = 0x00; foo->lpad = 3; break; case 6: /* xxxxxx01 00000000 */ foo->dbits[1] |= 0x80; foo->dbits[2] = 0x00; foo->lpad = 2; break; case 7: /* * xxxxxxx0 * 00...... * 00000000 00000000 11111111 11111111 */ foo->dbits[2] = 0x00; foo->dbits[3] = 0x00; foo->dbits[4] = 0x00; foo->dbits[5] = 0xff; foo->dbits[6] = 0xff; foo->lpad = 6; break; case 0: /* xxxxxxxx */ default: WRONG("compiler must be broken"); } if (ved_bytes(foo->req, foo->preq, VDP_NULL, foo->dbits + 1, foo->lpad)) return (-1); } if (len > 0) { /* Recover GZIP tail */ dl = foo->olen - foo->ll; assert(dl >= 0); if (dl > len) dl = len; if (dl > 0) { assert(dl <= 8); l = foo->ll - (foo->olen - 8); assert(l >= 0); assert(l <= 8); assert(l + dl <= 8); memcpy(foo->tailbuf + l, pp, dl); foo->ll += dl; len -= dl; } } assert(len == 0); return (0); }