static int
cnt_error(struct sess *sp)
{
    struct worker *w;
    struct http *h;
    char date[40];

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);

    w = sp->wrk;
    if (sp->obj == NULL) {
        HSH_Prealloc(sp);
        sp->obj = HSH_NewObject(sp, 1);
        sp->obj->xid = sp->xid;
        sp->obj->entered = sp->t_req;
    } else {
        /* XXX: Null the headers ? */
    }
    CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
    h = sp->obj->http;

    http_PutProtocol(w, sp->fd, h, "HTTP/1.1");
    http_PutStatus(w, sp->fd, h, sp->err_code);
    TIM_format(TIM_real(), date);
    http_PrintfHeader(w, sp->fd, h, "Date: %s", date);
    http_PrintfHeader(w, sp->fd, h, "Server: Varnish");
    http_PrintfHeader(w, sp->fd, h, "Retry-After: %d", params->err_ttl);

    if (sp->err_reason != NULL)
        http_PutResponse(w, sp->fd, h, sp->err_reason);
    else
        http_PutResponse(w, sp->fd, h,
                         http_StatusMessage(sp->err_code));
    VCL_error_method(sp);

    if (sp->handling == VCL_RET_RESTART) {
        HSH_Drop(sp);
        sp->director = NULL;
        sp->restarts++;
        sp->step = STP_RECV;
        return (0);
    }

    /* We always close when we take this path */
    sp->doclose = "error";
    sp->wantbody = 1;

    assert(sp->handling == VCL_RET_DELIVER);
    sp->err_code = 0;
    sp->err_reason = NULL;
    sp->wrk->bereq = NULL;
    sp->step = STP_DELIVER;
    return (0);
}
Ejemplo n.º 2
0
static int
cnt_error(struct worker *wrk, struct req *req)
{
	struct http *h;
	struct busyobj *bo;
	char date[40];

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	AZ(req->objcore);
	AZ(req->obj);
	AZ(req->busyobj);

	bo = VBO_GetBusyObj(wrk, req);
	req->busyobj = bo;
	AZ(bo->stats);
	bo->stats = &wrk->stats;
	req->objcore = HSH_NewObjCore(wrk);
	req->obj = STV_NewObject(bo, &req->objcore,
	    TRANSIENT_STORAGE, cache_param->http_resp_size,
	    (uint16_t)cache_param->http_max_hdr);
	bo->stats = NULL;
	if (req->obj == NULL) {
		req->doclose = SC_OVERLOAD;
		req->director = NULL;
		http_Teardown(bo->beresp);
		http_Teardown(bo->bereq);
		return(1);
	}
	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	req->obj->vxid = bo->vsl->wid;
	req->obj->exp.entered = req->t_req;

	h = req->obj->http;

	if (req->err_code < 100 || req->err_code > 999)
		req->err_code = 501;

	http_PutProtocol(h, "HTTP/1.1");
	http_PutStatus(h, req->err_code);
	VTIM_format(W_TIM_real(wrk), date);
	http_PrintfHeader(h, "Date: %s", date);
	http_SetHeader(h, "Server: Varnish");

	if (req->err_reason != NULL)
		http_PutResponse(h, req->err_reason);
	else
		http_PutResponse(h, http_StatusMessage(req->err_code));
	VCL_error_method(req);

	if (req->handling == VCL_RET_RESTART &&
	    req->restarts <  cache_param->max_restarts) {
		HSH_Drop(wrk, &req->obj);
		VBO_DerefBusyObj(wrk, &req->busyobj);
		req->req_step = R_STP_RESTART;
		return (0);
	} else if (req->handling == VCL_RET_RESTART)
		req->handling = VCL_RET_DELIVER;


	/* We always close when we take this path */
	req->doclose = SC_TX_ERROR;
	req->wantbody = 1;

	assert(req->handling == VCL_RET_DELIVER);
	req->err_code = 0;
	req->err_reason = NULL;
	http_Teardown(bo->bereq);
	VBO_DerefBusyObj(wrk, &req->busyobj);
	req->req_step = R_STP_PREPRESP;
	return (0);
}
static int
cnt_fetch(struct sess *sp)
{
    int i, transient;
    struct http *hp, *hp2;
    char *b;
    unsigned handling;

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);

    AN(sp->director);
    AZ(sp->vbe);

    /* sp->wrk->http[0] is (still) bereq */
    sp->wrk->beresp = &sp->wrk->http[1];
    http_Setup(sp->wrk->beresp, sp->wrk->ws);

    i = FetchHdr(sp);

    /*
     * Save a copy before it might get mangled in VCL.  When it comes to
     * dealing with the body, we want to see the unadultered headers.
     */
    sp->wrk->beresp1 = &sp->wrk->http[2];
    *sp->wrk->beresp1 = *sp->wrk->beresp;

    if (i) {
        if (sp->objhead) {
            CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
            CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
            HSH_DerefObjCore(sp);
        }
        AZ(sp->obj);
        sp->wrk->bereq = NULL;
        sp->wrk->beresp = NULL;
        sp->wrk->beresp1 = NULL;
        sp->err_code = 503;
        sp->step = STP_ERROR;
        return (0);
    }

    sp->err_code = http_GetStatus(sp->wrk->beresp);

    /*
     * Initial cacheability determination per [RFC2616, 13.4]
     * We do not support ranges yet, so 206 is out.
     */
    switch (sp->err_code) {
    case 200: /* OK */
    case 203: /* Non-Authoritative Information */
    case 300: /* Multiple Choices */
    case 301: /* Moved Permanently */
    case 302: /* Moved Temporarily */
    case 410: /* Gone */
    case 404: /* Not Found */
        sp->wrk->cacheable = 1;
        break;
    default:
        sp->wrk->cacheable = 0;
        break;
    }

    sp->wrk->entered = TIM_real();
    sp->wrk->age = 0;
    sp->wrk->ttl = RFC2616_Ttl(sp);

    if (sp->wrk->ttl == 0.)
        sp->wrk->cacheable = 0;

    sp->wrk->do_esi = 0;
    sp->wrk->grace = NAN;

    VCL_fetch_method(sp);

    /*
     * When we fetch the body, we may hit the LRU cleanup and that
     * will overwrite sp->handling, so we have to save our plans
     * here.
     */
    handling = sp->handling;

    if (sp->objhead == NULL)
        transient = 1;
    else if (sp->handling == VCL_RET_DELIVER)
        transient = 0;
    else
        transient = 1;

    /*
     * XXX: If we have a Length: header, we should allocate the body
     * XXX: also.
     */
    sp->obj = HSH_NewObject(sp, transient);

    if (sp->objhead != NULL) {
        CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
        CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
        sp->objcore->obj = sp->obj;
        sp->obj->objcore = sp->objcore;
        sp->obj->objhead = sp->objhead;
        sp->objhead = NULL;	/* refcnt follows pointer. */
        sp->objcore = NULL;	/* refcnt follows pointer. */
    }

    BAN_NewObj(sp->obj);

    sp->obj->xid = sp->xid;
    sp->obj->response = sp->err_code;
    sp->obj->cacheable = sp->wrk->cacheable;
    sp->obj->ttl = sp->wrk->ttl;
    sp->obj->grace = sp->wrk->grace;
    if (sp->obj->ttl == 0. && sp->obj->grace == 0.)
        sp->obj->cacheable = 0;
    sp->obj->age = sp->wrk->age;
    sp->obj->entered = sp->wrk->entered;
    WS_Assert(sp->obj->ws_o);

    /* Filter into object */
    hp = sp->wrk->beresp;
    hp2 = sp->obj->http;

    hp2->logtag = HTTP_Obj;
    http_CopyResp(hp2, hp);
    http_FilterFields(sp->wrk, sp->fd, hp2, hp, HTTPH_A_INS);
    http_CopyHome(sp->wrk, sp->fd, hp2);

    if (http_GetHdr(hp, H_Last_Modified, &b))
        sp->obj->last_modified = TIM_parse(b);

    i = FetchBody(sp);
    AZ(sp->wrk->wfd);
    AZ(sp->vbe);
    AN(sp->director);

    if (i) {
        HSH_Drop(sp);
        AZ(sp->obj);
        sp->wrk->bereq = NULL;
        sp->wrk->beresp = NULL;
        sp->wrk->beresp1 = NULL;
        sp->err_code = 503;
        sp->step = STP_ERROR;
        return (0);
    }

    if (!transient)
        HSH_Object(sp);

    if (sp->wrk->do_esi)
        ESI_Parse(sp);

    switch (handling) {
    case VCL_RET_RESTART:
        HSH_Drop(sp);
        sp->director = NULL;
        sp->restarts++;
        sp->wrk->bereq = NULL;
        sp->wrk->beresp = NULL;
        sp->wrk->beresp1 = NULL;
        sp->step = STP_RECV;
        return (0);
    case VCL_RET_PASS:
        if (sp->obj->objcore != NULL)
            sp->obj->objcore->flags |= OC_F_PASS;
        if (sp->obj->ttl - sp->t_req < params->default_ttl)
            sp->obj->ttl = sp->t_req + params->default_ttl;
        break;
    case VCL_RET_DELIVER:
        break;
    case VCL_RET_ERROR:
        HSH_Drop(sp);
        sp->wrk->bereq = NULL;
        sp->wrk->beresp = NULL;
        sp->wrk->beresp1 = NULL;
        sp->step = STP_ERROR;
        return (0);
    default:
        WRONG("Illegal action in vcl_fetch{}");
    }

    sp->obj->cacheable = 1;
    if (sp->obj->objhead != NULL) {
        VRY_Create(sp);
        EXP_Insert(sp->obj);
        AN(sp->obj->ban);
        HSH_Unbusy(sp);
    }
    sp->acct_req.fetch++;
    sp->wrk->bereq = NULL;
    sp->wrk->beresp = NULL;
    sp->wrk->beresp1 = NULL;
    sp->step = STP_DELIVER;
    return (0);
}
Ejemplo n.º 4
0
static enum req_fsm_nxt
cnt_error(struct worker *wrk, struct req *req)
{
	struct http *h;
	struct busyobj *bo;
	char date[40];

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	AZ(req->objcore);
	AZ(req->obj);

	req->acct_req.error++;
	bo = VBO_GetBusyObj(wrk, req);
	AZ(bo->stats);
	bo->stats = &wrk->stats;
	bo->fetch_objcore = HSH_Private(wrk);
	bo->fetch_obj = STV_NewObject(bo,
	    TRANSIENT_STORAGE, cache_param->http_resp_size,
	    (uint16_t)cache_param->http_max_hdr);
	req->obj = bo->fetch_obj;
	bo->stats = NULL;
	if (req->obj == NULL) {
		req->doclose = SC_OVERLOAD;
		req->director = NULL;
		AZ(HSH_DerefObjCore(&wrk->stats, &bo->fetch_objcore));
		bo->fetch_objcore = NULL;
		http_Teardown(bo->beresp);
		http_Teardown(bo->bereq);
		VBO_DerefBusyObj(wrk, &bo);
		return (REQ_FSM_DONE);
	}
	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	AZ(req->objcore);
	req->obj->vxid = bo->vsl->wid;
	req->obj->exp.entered = req->t_req;

	h = req->obj->http;

	if (req->err_code < 100 || req->err_code > 999)
		req->err_code = 501;

	http_PutProtocol(h, "HTTP/1.1");
	http_PutStatus(h, req->err_code);
	VTIM_format(W_TIM_real(wrk), date);
	http_PrintfHeader(h, "Date: %s", date);
	http_SetHeader(h, "Server: Varnish");

	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	HSH_Ref(req->obj->objcore);

	if (req->err_reason != NULL)
		http_PutResponse(h, req->err_reason);
	else
		http_PutResponse(h, http_StatusMessage(req->err_code));
	VCL_error_method(req->vcl, wrk, req, NULL, req->http->ws);

	/* Stop the insanity before it turns "Hotel California" on us */
	if (req->restarts >= cache_param->max_restarts)
		wrk->handling = VCL_RET_DELIVER;

	if (wrk->handling == VCL_RET_RESTART) {
		VBO_DerefBusyObj(wrk, &bo);
		HSH_Drop(wrk, &req->obj);
		req->req_step = R_STP_RESTART;
		return (REQ_FSM_MORE);
	}
	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);

	/* We always close when we take this path */
	req->doclose = SC_TX_ERROR;
	req->wantbody = 1;

	assert(wrk->handling == VCL_RET_DELIVER);
	req->err_code = 0;
	req->err_reason = NULL;
	http_Teardown(bo->bereq);
	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	VBO_DerefBusyObj(wrk, &bo);
	req->req_step = R_STP_DELIVER;
	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	return (REQ_FSM_MORE);
}
Ejemplo n.º 5
0
static int
cnt_fetchbody(struct sess *sp)
{
    int i;
    struct http *hp, *hp2;
    char *b;
    uint16_t nhttp;
    unsigned l;
    struct vsb *vary = NULL;
    int varyl = 0, pass;
    struct worker *wrk;

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    wrk = sp->wrk;
    CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
    CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);

    assert(sp->handling == VCL_RET_HIT_FOR_PASS ||
           sp->handling == VCL_RET_DELIVER);

    if (wrk->objcore == NULL) {
        /* This is a pass from vcl_recv */
        pass = 1;
        /* VCL may have fiddled this, but that doesn't help */
        wrk->busyobj->exp.ttl = -1.;
    } else if (sp->handling == VCL_RET_HIT_FOR_PASS) {
        /* pass from vcl_fetch{} -> hit-for-pass */
        /* XXX: the bereq was not filtered pass... */
        pass = 1;
    } else {
        /* regular object */
        pass = 0;
    }

    /*
     * The VCL variables beresp.do_g[un]zip tells us how we want the
     * object processed before it is stored.
     *
     * The backend Content-Encoding header tells us what we are going
     * to receive, which we classify in the following three classes:
     *
     *	"Content-Encoding: gzip"	--> object is gzip'ed.
     *	no Content-Encoding		--> object is not gzip'ed.
     *	anything else			--> do nothing wrt gzip
     *
     */

    /* We do nothing unless the param is set */
    if (!cache_param->http_gzip_support)
        wrk->busyobj->do_gzip = wrk->busyobj->do_gunzip = 0;

    wrk->busyobj->is_gzip =
        http_HdrIs(wrk->busyobj->beresp, H_Content_Encoding, "gzip");

    wrk->busyobj->is_gunzip =
        !http_GetHdr(wrk->busyobj->beresp, H_Content_Encoding, NULL);

    /* It can't be both */
    assert(wrk->busyobj->is_gzip == 0 || wrk->busyobj->is_gunzip == 0);

    /* We won't gunzip unless it is gzip'ed */
    if (wrk->busyobj->do_gunzip && !wrk->busyobj->is_gzip)
        wrk->busyobj->do_gunzip = 0;

    /* If we do gunzip, remove the C-E header */
    if (wrk->busyobj->do_gunzip)
        http_Unset(wrk->busyobj->beresp, H_Content_Encoding);

    /* We wont gzip unless it is ungziped */
    if (wrk->busyobj->do_gzip && !wrk->busyobj->is_gunzip)
        wrk->busyobj->do_gzip = 0;

    /* If we do gzip, add the C-E header */
    if (wrk->busyobj->do_gzip)
        http_SetHeader(wrk, sp->vsl_id, wrk->busyobj->beresp,
                       "Content-Encoding: gzip");

    /* But we can't do both at the same time */
    assert(wrk->busyobj->do_gzip == 0 || wrk->busyobj->do_gunzip == 0);

    /* ESI takes precedence and handles gzip/gunzip itself */
    if (wrk->busyobj->do_esi)
        wrk->busyobj->vfp = &vfp_esi;
    else if (wrk->busyobj->do_gunzip)
        wrk->busyobj->vfp = &vfp_gunzip;
    else if (wrk->busyobj->do_gzip)
        wrk->busyobj->vfp = &vfp_gzip;
    else if (wrk->busyobj->is_gzip)
        wrk->busyobj->vfp = &vfp_testgzip;

    if (wrk->busyobj->do_esi || sp->esi_level > 0)
        wrk->busyobj->do_stream = 0;
    if (!sp->wantbody)
        wrk->busyobj->do_stream = 0;

    l = http_EstimateWS(wrk->busyobj->beresp,
                        pass ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp);

    /* Create Vary instructions */
    if (wrk->objcore != NULL) {
        CHECK_OBJ_NOTNULL(wrk->objcore, OBJCORE_MAGIC);
        vary = VRY_Create(sp, wrk->busyobj->beresp);
        if (vary != NULL) {
            varyl = VSB_len(vary);
            assert(varyl > 0);
            l += varyl;
        }
    }

    /*
     * Space for producing a Content-Length: header including padding
     * A billion gigabytes is enough for anybody.
     */
    l += strlen("Content-Length: XxxXxxXxxXxxXxxXxx") + sizeof(void *);

    if (wrk->busyobj->exp.ttl < cache_param->shortlived ||
            wrk->objcore == NULL)
        wrk->storage_hint = TRANSIENT_STORAGE;

    wrk->obj = STV_NewObject(wrk, wrk->storage_hint, l, nhttp);
    if (wrk->obj == NULL) {
        /*
         * Try to salvage the transaction by allocating a
         * shortlived object on Transient storage.
         */
        wrk->obj = STV_NewObject(wrk, TRANSIENT_STORAGE, l, nhttp);
        if (wrk->busyobj->exp.ttl > cache_param->shortlived)
            wrk->busyobj->exp.ttl = cache_param->shortlived;
        wrk->busyobj->exp.grace = 0.0;
        wrk->busyobj->exp.keep = 0.0;
    }
    if (wrk->obj == NULL) {
        sp->err_code = 503;
        sp->step = STP_ERROR;
        VDI_CloseFd(wrk, &wrk->busyobj->vbc);
        VBO_DerefBusyObj(wrk, &wrk->busyobj);
        return (0);
    }
    CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC);

    wrk->storage_hint = NULL;

    if (wrk->busyobj->do_gzip ||
            (wrk->busyobj->is_gzip && !wrk->busyobj->do_gunzip))
        wrk->obj->gziped = 1;

    if (vary != NULL) {
        wrk->obj->vary = (void *)WS_Alloc(wrk->obj->http->ws, varyl);
        AN(wrk->obj->vary);
        memcpy(wrk->obj->vary, VSB_data(vary), varyl);
        VRY_Validate(wrk->obj->vary);
        VSB_delete(vary);
    }

    wrk->obj->xid = sp->xid;
    wrk->obj->response = sp->err_code;
    WS_Assert(wrk->obj->ws_o);

    /* Filter into object */
    hp = wrk->busyobj->beresp;
    hp2 = wrk->obj->http;

    hp2->logtag = HTTP_Obj;
    http_CopyResp(hp2, hp);
    http_FilterFields(wrk, sp->vsl_id, hp2, hp,
                      pass ? HTTPH_R_PASS : HTTPH_A_INS);
    http_CopyHome(wrk, sp->vsl_id, hp2);

    if (http_GetHdr(hp, H_Last_Modified, &b))
        wrk->obj->last_modified = VTIM_parse(b);
    else
        wrk->obj->last_modified = floor(wrk->busyobj->exp.entered);

    assert(WRW_IsReleased(wrk));

    /*
     * If we can deliver a 304 reply, we don't bother streaming.
     * Notice that vcl_deliver{} could still nuke the headers
     * that allow the 304, in which case we return 200 non-stream.
     */
    if (wrk->obj->response == 200 &&
            sp->http->conds &&
            RFC2616_Do_Cond(sp))
        wrk->busyobj->do_stream = 0;

    AssertObjCorePassOrBusy(wrk->obj->objcore);

    if (wrk->busyobj->do_stream) {
        sp->step = STP_PREPRESP;
        return (0);
    }

    /* Use unmodified headers*/
    i = FetchBody(wrk, wrk->obj);

    http_Setup(wrk->busyobj->bereq, NULL);
    http_Setup(wrk->busyobj->beresp, NULL);
    wrk->busyobj->vfp = NULL;
    assert(WRW_IsReleased(wrk));
    AZ(wrk->busyobj->vbc);
    AN(sp->director);

    if (i) {
        HSH_Drop(wrk);
        VBO_DerefBusyObj(wrk, &wrk->busyobj);
        AZ(wrk->obj);
        sp->err_code = 503;
        sp->step = STP_ERROR;
        return (0);
    }

    if (wrk->obj->objcore != NULL) {
        EXP_Insert(wrk->obj);
        AN(wrk->obj->objcore);
        AN(wrk->obj->objcore->ban);
        HSH_Unbusy(wrk);
    }
    VBO_DerefBusyObj(wrk, &wrk->busyobj);
    wrk->acct_tmp.fetch++;
    sp->step = STP_PREPRESP;
    return (0);
}
Ejemplo n.º 6
0
static int
cnt_error(struct sess *sp)
{
    struct http *h;
    char date[40];
    struct worker *wrk;

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    wrk = sp->wrk;
    CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);

    if (wrk->obj == NULL) {
        HSH_Prealloc(sp);
        AZ(wrk->busyobj);
        wrk->busyobj = VBO_GetBusyObj(wrk);
        wrk->obj = STV_NewObject(wrk, NULL, cache_param->http_resp_size,
                                 (uint16_t)cache_param->http_max_hdr);
        if (wrk->obj == NULL)
            wrk->obj = STV_NewObject(wrk, TRANSIENT_STORAGE,
                                     cache_param->http_resp_size,
                                     (uint16_t)cache_param->http_max_hdr);
        if (wrk->obj == NULL) {
            sp->doclose = "Out of objects";
            sp->director = NULL;
            http_Setup(wrk->busyobj->beresp, NULL);
            http_Setup(wrk->busyobj->bereq, NULL);
            sp->step = STP_DONE;
            return(0);
        }
        AN(wrk->obj);
        wrk->obj->xid = sp->xid;
        wrk->obj->exp.entered = sp->t_req;
    } else {
        CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);
        /* XXX: Null the headers ? */
    }
    CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC);
    h = wrk->obj->http;

    if (sp->err_code < 100 || sp->err_code > 999)
        sp->err_code = 501;

    http_PutProtocol(wrk, sp->vsl_id, h, "HTTP/1.1");
    http_PutStatus(h, sp->err_code);
    VTIM_format(W_TIM_real(wrk), date);
    http_PrintfHeader(wrk, sp->vsl_id, h, "Date: %s", date);
    http_SetHeader(wrk, sp->vsl_id, h, "Server: Varnish");

    if (sp->err_reason != NULL)
        http_PutResponse(wrk, sp->vsl_id, h, sp->err_reason);
    else
        http_PutResponse(wrk, sp->vsl_id, h,
                         http_StatusMessage(sp->err_code));
    VCL_error_method(sp);

    if (sp->handling == VCL_RET_RESTART &&
            sp->restarts <  cache_param->max_restarts) {
        HSH_Drop(wrk);
        VBO_DerefBusyObj(wrk, &wrk->busyobj);
        sp->director = NULL;
        sp->restarts++;
        sp->step = STP_RECV;
        return (0);
    } else if (sp->handling == VCL_RET_RESTART)
        sp->handling = VCL_RET_DELIVER;


    /* We always close when we take this path */
    sp->doclose = "error";
    sp->wantbody = 1;

    assert(sp->handling == VCL_RET_DELIVER);
    sp->err_code = 0;
    sp->err_reason = NULL;
    http_Setup(wrk->busyobj->bereq, NULL);
    VBO_DerefBusyObj(wrk, &wrk->busyobj);
    sp->step = STP_PREPRESP;
    return (0);
}
Ejemplo n.º 7
0
static int
cnt_prepresp(struct sess *sp)
{
    struct worker *wrk;

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    wrk = sp->wrk;
    CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);

    CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC);
    CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);

    if (wrk->busyobj != NULL) {
        CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);
        AN(wrk->busyobj->do_stream);
        AssertObjCorePassOrBusy(wrk->obj->objcore);
    }

    wrk->res_mode = 0;

    if (wrk->busyobj == NULL)
        wrk->res_mode |= RES_LEN;

    if (wrk->busyobj != NULL &&
            (wrk->busyobj->h_content_length != NULL ||
             !wrk->busyobj->do_stream) &&
            !wrk->busyobj->do_gzip && !wrk->busyobj->do_gunzip)
        wrk->res_mode |= RES_LEN;

    if (!sp->disable_esi && wrk->obj->esidata != NULL) {
        /* In ESI mode, we don't know the aggregate length */
        wrk->res_mode &= ~RES_LEN;
        wrk->res_mode |= RES_ESI;
    }

    if (sp->esi_level > 0) {
        wrk->res_mode &= ~RES_LEN;
        wrk->res_mode |= RES_ESI_CHILD;
    }

    if (cache_param->http_gzip_support && wrk->obj->gziped &&
            !RFC2616_Req_Gzip(sp)) {
        /*
         * We don't know what it uncompresses to
         * XXX: we could cache that
         */
        wrk->res_mode &= ~RES_LEN;
        wrk->res_mode |= RES_GUNZIP;
    }

    if (!(wrk->res_mode & (RES_LEN|RES_CHUNKED|RES_EOF))) {
        if (wrk->obj->len == 0 &&
                (wrk->busyobj == NULL || !wrk->busyobj->do_stream))
            /*
             * If the object is empty, neither ESI nor GUNZIP
             * can make it any different size
             */
            wrk->res_mode |= RES_LEN;
        else if (!sp->wantbody) {
            /* Nothing */
        } else if (sp->http->protover >= 11) {
            wrk->res_mode |= RES_CHUNKED;
        } else {
            wrk->res_mode |= RES_EOF;
            sp->doclose = "EOF mode";
        }
    }

    sp->t_resp = W_TIM_real(wrk);
    if (wrk->obj->objcore != NULL) {
        if ((sp->t_resp - wrk->obj->last_lru) >
                cache_param->lru_timeout &&
                EXP_Touch(wrk->obj->objcore))
            wrk->obj->last_lru = sp->t_resp;
        wrk->obj->last_use = sp->t_resp;	/* XXX: locking ? */
    }
    http_Setup(wrk->resp, wrk->ws);
    RES_BuildHttp(sp);
    VCL_deliver_method(sp);
    switch (sp->handling) {
    case VCL_RET_DELIVER:
        break;
    case VCL_RET_RESTART:
        if (sp->restarts >= cache_param->max_restarts)
            break;
        if (wrk->busyobj != NULL) {
            AN(wrk->busyobj->do_stream);
            VDI_CloseFd(wrk, &wrk->busyobj->vbc);
            HSH_Drop(wrk);
            VBO_DerefBusyObj(wrk, &wrk->busyobj);
        } else {
            (void)HSH_Deref(wrk, NULL, &wrk->obj);
        }
        AZ(wrk->obj);
        sp->restarts++;
        sp->director = NULL;
        http_Setup(wrk->resp, NULL);
        sp->step = STP_RECV;
        return (0);
    default:
        WRONG("Illegal action in vcl_deliver{}");
    }
    if (wrk->busyobj != NULL && wrk->busyobj->do_stream) {
        AssertObjCorePassOrBusy(wrk->obj->objcore);
        sp->step = STP_STREAMBODY;
    } else {
        sp->step = STP_DELIVER;
    }
    return (0);
}