v1d_range_bytes(struct req *req, enum vdp_action act, const void *ptr, ssize_t len) { int retval = 0; ssize_t l; const char *p = ptr; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); l = req->range_low - req->range_off; if (l > 0) { if (l > len) l = len; req->range_off += l; p += l; len -= l; } l = req->range_high - req->range_off; if (l > len) l = len; if (l > 0) retval = VDP_bytes(req, act, p, l); else if (act > VDP_NULL) retval = VDP_bytes(req, act, p, 0); req->range_off += len; return (retval); }
static void v1d_WriteDirObj(struct req *req) { enum objiter_status ois; ssize_t len; struct objiter *oi; void *ptr; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); oi = ObjIterBegin(req->wrk, req->obj); XXXAN(oi); do { ois = ObjIter(oi, &ptr, &len); switch(ois) { case OIS_DONE: AZ(len); break; case OIS_ERROR: break; case OIS_DATA: case OIS_STREAM: if (VDP_bytes(req, ois == OIS_DATA ? VDP_NULL : VDP_FLUSH, ptr, len)) ois = OIS_ERROR; break; default: WRONG("Wrong OIS value"); } } while (ois == OIS_DATA || ois == OIS_STREAM); (void)VDP_bytes(req, VDP_FINISH, NULL, 0); ObjIterEnd(&oi); }
/* * Account body bytes on req * Push bytes to preq */ static inline int ved_bytes(struct req *req, struct req *preq, enum vdp_action act, const void *ptr, ssize_t len) { req->acct.resp_bodybytes += len; return (VDP_bytes(preq, act, ptr, len)); }
VED_Deliver(struct req *req, struct boc *boc, int wantbody) { int i; struct ecx *ecx; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_ORNULL(boc, BOC_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC); if (wantbody == 0) return; req->res_mode |= RES_ESI_CHILD; i = ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED); if (ecx->isgzip && i && !(req->res_mode & RES_ESI)) { ved_stripgzip(req, boc); } else { if (ecx->isgzip && !i) VDP_push(req, ved_pretend_gzip, ecx, 1); else VDP_push(req, ved_vdp_bytes, ecx->preq, 1); (void)VDP_DeliverObj(req); (void)VDP_bytes(req, VDP_FLUSH, NULL, 0); } VDP_close(req); }
VDP_dump(struct req *req, enum vdp_action act, void **priv, const void *ptr, ssize_t len) { //priv fmt // flg(Complete the header output)@1Byte + [workspace] if (act == VDP_INIT){ VSLb(req->vsl, SLT_Debug,"%s-S: RES", VMOD_DUMP_PRE); VSLb(req->vsl, SLT_Debug,"%s-V: %s", VMOD_DUMP_PRE, (char *)*priv); *priv = malloc(cache_param->vsl_reclen + 1); AN(*priv); *((char **)priv)[0] = 0; return(0); }else if(act == VDP_FINI){ VSLb(req->vsl, SLT_Debug,"%s-S: END", VMOD_DUMP_PRE); free(*priv); *priv = NULL; return(0); } if(len){ if(*((char **)priv)[0] == 0){ work_head(req, *priv+1, cache_param->vsl_reclen, req->resp,HTTP1_Resp); *((char **)priv)[0] = 1; } work_body(req, *priv+1, cache_param->vsl_reclen, (void*)ptr, len, req->resp); } return(VDP_bytes(req, act, ptr, len)); }
VDP_gunzip(struct req *req, enum vdp_action act, const void *ptr, ssize_t len) { enum vgzret_e vr; size_t dl; const void *dp; struct worker *wrk; struct vgz *vg; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); wrk = req->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); vg = req->vgz; CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); AN(vg->m_buf); if (len == 0) { AN(act > VDP_NULL); return (VDP_bytes(req, act, vg->m_buf, vg->m_len)); } VGZ_Ibuf(vg, ptr, len); do { if (vg->m_len == vg->m_sz) vr = VGZ_STUCK; else { vr = VGZ_Gunzip(vg, &dp, &dl); vg->m_len += dl; } if (vr < VGZ_OK) return (-1); if (vg->m_len == vg->m_sz || vr == VGZ_STUCK) { if (VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len)) return (-1); vg->m_len = 0; VGZ_Obuf(vg, vg->m_buf, vg->m_sz); } } while (!VGZ_IbufEmpty(vg)); assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END); return (0); }
enum objiter_status VDP_DeliverObj(struct req *req) { enum objiter_status ois; ssize_t len; void *oi; void *ptr; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); oi = ObjIterBegin(req->wrk, req->objcore); XXXAN(oi); AZ(req->synth_body); do { ois = ObjIter(req->objcore, oi, &ptr, &len); switch(ois) { case OIS_DONE: AZ(len); break; case OIS_ERROR: break; case OIS_DATA: case OIS_STREAM: if (VDP_bytes(req, ois == OIS_DATA ? VDP_NULL : VDP_FLUSH, ptr, len)) ois = OIS_ERROR; break; default: WRONG("Wrong OIS value"); } } while (ois == OIS_DATA || ois == OIS_STREAM); (void)VDP_bytes(req, VDP_FLUSH, NULL, 0); ObjIterEnd(req->objcore, &oi); return (ois); }
void VGZ_WrwFlush(struct req *req, struct vgz *vg) { struct worker *wrk; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); wrk = req->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); if (vg->m_len == 0) return; (void)VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len); vg->m_len = 0; VGZ_Obuf(vg, vg->m_buf, vg->m_sz); }
enum vgzret_e VGZ_WrwGunzip(struct req *req, struct vgz *vg, const void *ibuf, ssize_t ibufl) { enum vgzret_e vr; size_t dl; const void *dp; struct worker *wrk; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); wrk = req->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); AN(vg->m_buf); VGZ_Ibuf(vg, ibuf, ibufl); if (ibufl == 0) return (VGZ_OK); do { if (vg->m_len == vg->m_sz) vr = VGZ_STUCK; else { vr = VGZ_Gunzip(vg, &dp, &dl); vg->m_len += dl; } if (vr < VGZ_OK) return (vr); if (vg->m_len == vg->m_sz || vr == VGZ_STUCK) { (void)VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len); vg->m_len = 0; VGZ_Obuf(vg, vg->m_buf, vg->m_sz); } } while (!VGZ_IbufEmpty(vg)); if (vr == VGZ_STUCK) vr = VGZ_OK; return (vr); }
VDP_ESI(struct req *req, enum vdp_action act, void **priv, const void *ptr, ssize_t len) { uint8_t *q, *r; ssize_t l = 0; uint32_t icrc = 0; uint8_t tailbuf[8 + 5]; const uint8_t *pp; struct ecx *ecx, *pecx; int retval = 0; if (act == VDP_INIT) { AZ(*priv); ALLOC_OBJ(ecx, ECX_MAGIC); AN(ecx); ecx->preq = req; *priv = ecx; return (0); } CAST_OBJ_NOTNULL(ecx, *priv, ECX_MAGIC); if (act == VDP_FINI) { FREE_OBJ(ecx); *priv = NULL; return (0); } pp = ptr; while (1) { switch (ecx->state) { case 0: ecx->p = ObjGetattr(req->wrk, req->objcore, OA_ESIDATA, &l); AN(ecx->p); assert(l > 0); ecx->e = ecx->p + l; if (*ecx->p == VEC_GZ) { ecx->isgzip = 1; ecx->p++; } if (req->esi_level == 0) { /* * Only the top level document gets to * decide this. */ if (ecx->isgzip) { assert(sizeof gzip_hdr == 10); /* Send out the gzip header */ retval = VDP_bytes(req, VDP_NULL, gzip_hdr, 10); ecx->l_crc = 0; ecx->crc = crc32(0L, Z_NULL, 0); } } ecx->state = 1; break; case 1: if (ecx->p >= ecx->e) { ecx->state = 2; break; } switch (*ecx->p) { case VEC_V1: case VEC_V2: case VEC_V8: ecx->l = ved_decode_len(req, &ecx->p); if (ecx->l < 0) return (-1); if (ecx->isgzip) { assert(*ecx->p == VEC_C1 || *ecx->p == VEC_C2 || *ecx->p == VEC_C8); l = ved_decode_len(req, &ecx->p); if (l < 0) return (-1); icrc = vbe32dec(ecx->p); ecx->p += 4; if (ecx->isgzip) { ecx->crc = crc32_combine( ecx->crc, icrc, l); ecx->l_crc += l; } } ecx->state = 3; break; case VEC_S1: case VEC_S2: case VEC_S8: ecx->l = ved_decode_len(req, &ecx->p); if (ecx->l < 0) return (-1); Debug("SKIP1(%d)\n", (int)ecx->l); ecx->state = 4; break; case VEC_INCL: ecx->p++; q = (void*)strchr((const char*)ecx->p, '\0'); AN(q); q++; r = (void*)strchr((const char*)q, '\0'); AN(r); if (VDP_bytes(req, VDP_FLUSH, NULL, 0)) { ecx->p = ecx->e; break; } Debug("INCL [%s][%s] BEGIN\n", q, ecx->p); ved_include(req, (const char*)q, (const char*)ecx->p, ecx); Debug("INCL [%s][%s] END\n", q, ecx->p); ecx->p = r + 1; break; default: VSLb(req->vsl, SLT_Error, "ESI corruption line %d 0x%02x [%s]\n", __LINE__, *ecx->p, ecx->p); WRONG("ESI-codes: Illegal code"); } break; case 2: if (ecx->isgzip && req->esi_level == 0) { /* * We are bytealigned here, so simply emit * a gzip literal block with finish bit set. */ tailbuf[0] = 0x01; tailbuf[1] = 0x00; tailbuf[2] = 0x00; tailbuf[3] = 0xff; tailbuf[4] = 0xff; /* Emit CRC32 */ vle32enc(tailbuf + 5, ecx->crc); /* MOD(2^32) length */ vle32enc(tailbuf + 9, ecx->l_crc); (void)VDP_bytes(req, VDP_NULL, tailbuf, 13); } if (req->transport->deliver == VED_Deliver) { CAST_OBJ_NOTNULL(pecx, req->transport_priv, ECX_MAGIC); pecx->crc = crc32_combine(pecx->crc, ecx->crc, ecx->l_crc); pecx->l_crc += ecx->l_crc; } retval = VDP_bytes(req, VDP_FLUSH, NULL, 0); ecx->state = 99; return (retval); case 3: case 4: /* * There is no guarantee that the 'l' bytes are all * in the same storage segment, so loop over storage * until we have processed them all. */ if (ecx->l <= len) { if (ecx->state == 3) retval = VDP_bytes(req, act, pp, ecx->l); len -= ecx->l; pp += ecx->l; ecx->state = 1; break; } if (ecx->state == 3 && len > 0) retval = VDP_bytes(req, act, pp, len); ecx->l -= len; return (retval); case 99: /* * VEP does not account for the PAD+CRC+LEN * so we can see up to approx 15 bytes here. */ return (retval); default: WRONG("FOO"); break; } if (retval) return (retval); } }
VDP_gunzip(struct req *req, enum vdp_action act, void **priv, const void *ptr, ssize_t len) { enum vgzret_e vr; ssize_t dl; const void *dp; struct worker *wrk; struct vgz *vg; const char *p; uint64_t u; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); wrk = req->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); if (act == VDP_INIT) { vg = VGZ_NewUngzip(req->vsl, "U D -"); AN(vg); if (vgz_getmbuf(vg)) { (void)VGZ_Destroy(&vg); return (-1); } req->res_mode |= RES_GUNZIP; VGZ_Obuf(vg, vg->m_buf, vg->m_sz); *priv = vg; http_Unset(req->resp, H_Content_Encoding); req->resp_len = -1; if (req->objcore->boc != NULL) return (0); /* No idea about length (yet) */ p = ObjGetAttr(req->wrk, req->objcore, OA_GZIPBITS, &dl); if (p == NULL || dl != 32) return (0); /* No OA_GZIPBITS yet */ u = vbe64dec(p + 24); /* * If the size is non-zero AND we are the top * VDP (ie: no ESI), we know what size the output will be. */ if (u != 0 && VTAILQ_FIRST(&req->vdp)->func == VDP_gunzip) req->resp_len = u; return (0); } CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC); AN(vg->m_buf); if (act == VDP_FINI) { /* NB: Gunzip'ing may or may not have completed successfully. */ AZ(len); (void)VGZ_Destroy(&vg); *priv = NULL; return (0); } if (len == 0) return (0); VGZ_Ibuf(vg, ptr, len); do { vr = VGZ_Gunzip(vg, &dp, &dl); vg->m_len += dl; if (vr < VGZ_OK) return (-1); if (vg->m_len == vg->m_sz || vr != VGZ_OK) { if (VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len)) return (req->vdp_retval); vg->m_len = 0; VGZ_Obuf(vg, vg->m_buf, vg->m_sz); } } while (!VGZ_IbufEmpty(vg)); assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END); return (0); }
VDP_gunzip(struct req *req, enum vdp_action act, void **priv, const void *ptr, ssize_t len) { enum vgzret_e vr; ssize_t dl; const void *dp; struct worker *wrk; struct vgz *vg; char *p; uint64_t u; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); wrk = req->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); if (act == VDP_INIT) { vg = VGZ_NewUngzip(req->vsl, "U D -"); AN(vg); if (vgz_getmbuf(vg)) { (void)VGZ_Destroy(&vg); return (-1); } VGZ_Obuf(vg, vg->m_buf, vg->m_sz); *priv = vg; http_Unset(req->resp, H_Content_Length); p = ObjGetattr(req->wrk, req->objcore, OA_GZIPBITS, &dl); if (p != NULL && dl == 32) { u = vbe64dec(p + 24); /* XXX: Zero is suspect: OA_GZIPBITS wasn't set */ if (u != 0) http_PrintfHeader(req->resp, "Content-Length: %ju", (uintmax_t)u); } http_Unset(req->resp, H_Content_Encoding); return (0); } CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC); AN(vg->m_buf); if (act == VDP_FINI) { /* NB: Gunzip'ing may or may not have completed successfully. */ AZ(len); (void)VGZ_Destroy(&vg); *priv = NULL; return (0); } if (len == 0) return (0); VGZ_Ibuf(vg, ptr, len); do { vr = VGZ_Gunzip(vg, &dp, &dl); vg->m_len += dl; if (vr < VGZ_OK) return (-1); if (vg->m_len == vg->m_sz || vr != VGZ_OK) { if (VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len)) return (-1); vg->m_len = 0; VGZ_Obuf(vg, vg->m_buf, vg->m_sz); } } while (!VGZ_IbufEmpty(vg)); assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END); return (0); }
void V1D_Deliver(struct req *req, struct busyobj *bo) { const char *r; enum objiter_status ois; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); req->res_mode = 0; /* * Determine ESI status first. Not dependent on wantbody, because * we want ESI to supress C-L in HEAD too. */ if (!req->disable_esi && ObjGetattr(req->wrk, req->objcore, OA_ESIDATA, NULL) != NULL) req->res_mode |= RES_ESI; /* * ESI-childen don't care about headers -> early escape */ if (req->esi_level > 0) { ESI_DeliverChild(req, bo); return; } if (req->res_mode & RES_ESI) { RFC2616_Weaken_Etag(req->resp); } else if (http_IsStatus(req->resp, 304)) { http_Unset(req->resp, H_Content_Length); req->wantbody = 0; } else if (bo == NULL && !http_GetHdr(req->resp, H_Content_Length, NULL)) { http_PrintfHeader(req->resp, "Content-Length: %ju", (uintmax_t)ObjGetLen( req->wrk, req->objcore)); } if (cache_param->http_gzip_support && ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED) && !RFC2616_Req_Gzip(req->http)) { /* * We don't know what it uncompresses to * XXX: we could cache that, but would still deliver * XXX: with multiple writes because of the gunzip buffer */ req->res_mode |= RES_GUNZIP; VDP_push(req, VDP_gunzip, NULL, 0); } if (req->res_mode & RES_ESI) { /* Gunzip could have added back a C-L */ http_Unset(req->resp, H_Content_Length); } /* * Range comes after the others and pushes on bottom because it * can generate a correct C-L header. */ if (cache_param->http_range_support && http_IsStatus(req->resp, 200)) { http_SetHeader(req->resp, "Accept-Ranges: bytes"); if (req->wantbody && http_GetHdr(req->http, H_Range, &r)) VRG_dorange(req, bo, r); } if (http_GetHdr(req->resp, H_Content_Length, NULL)) req->res_mode |= RES_LEN; if (req->wantbody && !(req->res_mode & RES_LEN)) { if (req->http->protover >= 11) { req->res_mode |= RES_CHUNKED; http_SetHeader(req->resp, "Transfer-Encoding: chunked"); } else { req->res_mode |= RES_EOF; req->doclose = SC_TX_EOF; } } VSLb(req->vsl, SLT_Debug, "RES_MODE %x", req->res_mode); if (req->doclose) { if (!http_HdrIs(req->resp, H_Connection, "close")) { http_Unset(req->resp, H_Connection); http_SetHeader(req->resp, "Connection: close"); } } else if (!http_GetHdr(req->resp, H_Connection, NULL)) http_SetHeader(req->resp, "Connection: keep-alive"); VDP_push(req, v1d_bytes, NULL, 1); V1L_Reserve(req->wrk, req->ws, &req->sp->fd, req->vsl, req->t_prev); req->acct.resp_hdrbytes += HTTP1_Write(req->wrk, req->resp, HTTP1_Resp); if (DO_DEBUG(DBG_FLUSH_HEAD)) (void)V1L_Flush(req->wrk); ois = OIS_DONE; if (req->wantbody) { if (req->res_mode & RES_CHUNKED) V1L_Chunked(req->wrk); ois = VDP_DeliverObj(req); (void)VDP_bytes(req, VDP_FLUSH, NULL, 0); if (ois == OIS_DONE && (req->res_mode & RES_CHUNKED)) V1L_EndChunk(req->wrk); } if ((V1L_FlushRelease(req->wrk) || ois != OIS_DONE) && req->sp->fd >= 0) SES_Close(req->sp, SC_REM_CLOSE); VDP_close(req); }