Exemplo n.º 1
0
static int
cnt_pipe(struct sess *sp)
{
    struct worker *wrk;

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    wrk = sp->wrk;
    CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
    CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
    AZ(wrk->busyobj);

    wrk->acct_tmp.pipe++;
    wrk->busyobj = VBO_GetBusyObj(wrk);
    WS_Reset(wrk->ws, NULL);
    wrk->busyobj = VBO_GetBusyObj(wrk);
    http_Setup(wrk->busyobj->bereq, wrk->ws);
    http_FilterHeader(sp, HTTPH_R_PIPE);

    VCL_pipe_method(sp);

    if (sp->handling == VCL_RET_ERROR)
        INCOMPL();
    assert(sp->handling == VCL_RET_PIPE);

    PipeSession(sp);
    assert(WRW_IsReleased(wrk));
    http_Setup(wrk->busyobj->bereq, NULL);
    VBO_DerefBusyObj(wrk, &wrk->busyobj);
    sp->step = STP_DONE;
    return (0);
}
Exemplo n.º 2
0
static int
cnt_pass(struct sess *sp)
{
    struct worker *wrk;

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    wrk = sp->wrk;
    CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
    CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
    AZ(wrk->obj);
    AZ(wrk->busyobj);

    wrk->busyobj = VBO_GetBusyObj(wrk);
    WS_Reset(wrk->ws, NULL);
    wrk->busyobj = VBO_GetBusyObj(wrk);
    http_Setup(wrk->busyobj->bereq, wrk->ws);
    http_FilterHeader(sp, HTTPH_R_PASS);

    wrk->connect_timeout = 0;
    wrk->first_byte_timeout = 0;
    wrk->between_bytes_timeout = 0;
    VCL_pass_method(sp);
    if (sp->handling == VCL_RET_ERROR) {
        http_Setup(wrk->busyobj->bereq, NULL);
        VBO_DerefBusyObj(wrk, &wrk->busyobj);
        sp->step = STP_ERROR;
        return (0);
    }
    assert(sp->handling == VCL_RET_PASS);
    wrk->acct_tmp.pass++;
    sp->sendbody = 1;
    sp->step = STP_FETCH;
    return (0);
}
static int
cnt_pipe(struct sess *sp)
{

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

    sp->acct_req.pipe++;
    WS_Reset(sp->wrk->ws, NULL);
    sp->wrk->bereq = &sp->wrk->http[0];
    http_Setup(sp->wrk->bereq, sp->wrk->ws);
    http_FilterHeader(sp, HTTPH_R_PIPE);

    VCL_pipe_method(sp);

    if (sp->handling == VCL_RET_ERROR)
        INCOMPL();
    assert(sp->handling == VCL_RET_PIPE);

    PipeSession(sp);
    AZ(sp->wrk->wfd);
    sp->wrk->bereq = NULL;
    sp->step = STP_DONE;
    return (0);
}
static int
cnt_miss(struct sess *sp)
{

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

    AZ(sp->obj);
    AN(sp->objcore);
    AN(sp->objhead);
    WS_Reset(sp->wrk->ws, NULL);
    sp->wrk->bereq = &sp->wrk->http[0];
    http_Setup(sp->wrk->bereq, sp->wrk->ws);
    http_FilterHeader(sp, HTTPH_R_FETCH);
    VCL_miss_method(sp);
    switch(sp->handling) {
    case VCL_RET_ERROR:
        HSH_DerefObjCore(sp);
        sp->step = STP_ERROR;
        return (0);
    case VCL_RET_PASS:
        HSH_DerefObjCore(sp);
        sp->step = STP_PASS;
        return (0);
    case VCL_RET_FETCH:
        sp->step = STP_FETCH;
        return (0);
    case VCL_RET_RESTART:
        HSH_DerefObjCore(sp);
        INCOMPL();
    default:
        WRONG("Illegal action in vcl_miss{}");
    }
}
static int
cnt_deliver(struct sess *sp)
{

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

    sp->t_resp = TIM_real();
    if (sp->obj->objhead != NULL) {
        if ((sp->t_resp - sp->obj->last_lru) > params->lru_timeout &&
                EXP_Touch(sp->obj))
            sp->obj->last_lru = sp->t_resp;	/* XXX: locking ? */
        sp->obj->last_use = sp->t_resp;	/* XXX: locking ? */
    }
    sp->wrk->resp = &sp->wrk->http[2];
    http_Setup(sp->wrk->resp, sp->wrk->ws);
    RES_BuildHttp(sp);
    VCL_deliver_method(sp);
    switch (sp->handling) {
    case VCL_RET_DELIVER:
        break;
    case VCL_RET_RESTART:
        INCOMPL();
        break;
    default:
        WRONG("Illegal action in vcl_deliver{}");
    }

    sp->director = NULL;
    sp->restarts = 0;

    RES_WriteObj(sp);
    AZ(sp->wrk->wfd);
    HSH_Deref(sp->wrk, &sp->obj);
    sp->wrk->resp = NULL;
    sp->step = STP_DONE;
    return (0);
}
Exemplo n.º 6
0
static int
cnt_deliver(struct sess *sp)
{
    struct worker *wrk;

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

    AZ(sp->wrk->busyobj);
    sp->director = NULL;
    sp->restarts = 0;

    RES_WriteObj(sp);

    assert(WRW_IsReleased(wrk));
    assert(wrk->wrw.ciov == wrk->wrw.siov);
    (void)HSH_Deref(wrk, NULL, &wrk->obj);
    http_Setup(wrk->resp, NULL);
    sp->step = STP_DONE;
    return (0);
}
static int
cnt_pass(struct sess *sp)
{

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

    WS_Reset(sp->wrk->ws, NULL);
    sp->wrk->bereq = &sp->wrk->http[0];
    http_Setup(sp->wrk->bereq, sp->wrk->ws);
    http_FilterHeader(sp, HTTPH_R_PASS);

    VCL_pass_method(sp);
    if (sp->handling == VCL_RET_ERROR) {
        sp->step = STP_ERROR;
        return (0);
    }
    assert(sp->handling == VCL_RET_PASS);
    sp->acct_req.pass++;
    sp->sendbody = 1;
    sp->step = STP_FETCH;
    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);
}
static int
cnt_start(struct sess *sp)
{
    int done;
    char *p;
    const char *r = "HTTP/1.1 100 Continue\r\n\r\n";

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    AZ(sp->restarts);
    AZ(sp->obj);
    AZ(sp->vcl);

    /* Update stats of various sorts */
    VSL_stats->client_req++;			/* XXX not locked */
    sp->t_req = TIM_real();
    sp->wrk->lastused = sp->t_req;
    sp->acct_req.req++;

    /* Assign XID and log */
    sp->xid = ++xids;				/* XXX not locked */
    WSP(sp, SLT_ReqStart, "%s %s %u", sp->addr, sp->port,  sp->xid);

    /* Borrow VCL reference from worker thread */
    VCL_Refresh(&sp->wrk->vcl);
    sp->vcl = sp->wrk->vcl;
    sp->wrk->vcl = NULL;

    http_Setup(sp->http, sp->ws);
    done = http_DissectRequest(sp);

    /* Catch request snapshot */
    sp->ws_req = WS_Snapshot(sp->ws);

    /* Catch original request, before modification */
    *sp->http0 = *sp->http;

    if (done != 0) {
        sp->err_code = done;
        sp->step = STP_ERROR;
        return (0);
    }

    sp->doclose = http_DoConnection(sp->http);

    /* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */

    /*
     * Handle Expect headers
     */
    if (http_GetHdr(sp->http, H_Expect, &p)) {
        if (strcmp(p, "100-continue")) {
            sp->err_code = 417;
            sp->step = STP_ERROR;
            return (0);
        }

        /* XXX: Don't bother with write failures for now */
        (void)write(sp->fd, r, strlen(r));
        /* XXX: When we do ESI includes, this is not removed
         * XXX: because we use http0 as our basis.  Believed
         * XXX: safe, but potentially confusing.
         */
        http_Unset(sp->http, H_Expect);
    }

    sp->step = STP_RECV;
    return (0);
}
Exemplo n.º 10
0
static int
cnt_streambody(struct sess *sp)
{
    int i;
    struct stream_ctx sctx;
    uint8_t obuf[sp->wrk->res_mode & RES_GUNZIP ?
                 cache_param->gzip_stack_buffer : 1];
    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);
    memset(&sctx, 0, sizeof sctx);
    sctx.magic = STREAM_CTX_MAGIC;
    AZ(wrk->sctx);
    wrk->sctx = &sctx;

    if (wrk->res_mode & RES_GUNZIP) {
        sctx.vgz = VGZ_NewUngzip(wrk, "U S -");
        sctx.obuf = obuf;
        sctx.obuf_len = sizeof (obuf);
    }

    RES_StreamStart(sp);

    AssertObjCorePassOrBusy(wrk->obj->objcore);

    i = FetchBody(wrk, wrk->obj);

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

    if (!i && wrk->obj->objcore != NULL) {
        EXP_Insert(wrk->obj);
        AN(wrk->obj->objcore);
        AN(wrk->obj->objcore->ban);
        HSH_Unbusy(wrk);
    } else {
        sp->doclose = "Stream error";
    }
    wrk->acct_tmp.fetch++;
    sp->director = NULL;
    sp->restarts = 0;

    RES_StreamEnd(sp);
    if (wrk->res_mode & RES_GUNZIP)
        (void)VGZ_Destroy(&sctx.vgz, sp->vsl_id);

    wrk->sctx = NULL;
    assert(WRW_IsReleased(wrk));
    assert(wrk->wrw.ciov == wrk->wrw.siov);
    (void)HSH_Deref(wrk, NULL, &wrk->obj);
    VBO_DerefBusyObj(wrk, &wrk->busyobj);
    http_Setup(wrk->resp, NULL);
    sp->step = STP_DONE;
    return (0);
}
Exemplo n.º 11
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);
}
Exemplo n.º 12
0
static int
cnt_fetch(struct sess *sp)
{
    int i, need_host_hdr;
    struct worker *wrk;

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

    CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
    CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);

    AN(sp->director);
    AZ(wrk->busyobj->vbc);
    AZ(wrk->busyobj->should_close);
    AZ(wrk->storage_hint);

    http_Setup(wrk->busyobj->beresp, wrk->ws);

    need_host_hdr = !http_GetHdr(wrk->busyobj->bereq, H_Host, NULL);

    i = FetchHdr(sp, need_host_hdr);
    /*
     * If we recycle a backend connection, there is a finite chance
     * that the backend closed it before we get a request to it.
     * Do a single retry in that case.
     */
    if (i == 1) {
        VSC_C_main->backend_retry++;
        i = FetchHdr(sp, need_host_hdr);
    }

    if (i) {
        sp->handling = VCL_RET_ERROR;
        sp->err_code = 503;
    } else {
        /*
         * These two headers can be spread over multiple actual headers
         * and we rely on their content outside of VCL, so collect them
         * into one line here.
         */
        http_CollectHdr(wrk->busyobj->beresp, H_Cache_Control);
        http_CollectHdr(wrk->busyobj->beresp, H_Vary);

        /*
         * Figure out how the fetch is supposed to happen, before the
         * headers are adultered by VCL
         * NB: Also sets other wrk variables
         */
        wrk->busyobj->body_status = RFC2616_Body(sp);

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

        /*
         * What does RFC2616 think about TTL ?
         */
        EXP_Clr(&wrk->busyobj->exp);
        wrk->busyobj->exp.entered = W_TIM_real(wrk);
        RFC2616_Ttl(sp);

        /* pass from vclrecv{} has negative TTL */
        if (wrk->objcore == NULL)
            wrk->busyobj->exp.ttl = -1.;

        AZ(wrk->busyobj->do_esi);

        VCL_fetch_method(sp);

        switch (sp->handling) {
        case VCL_RET_HIT_FOR_PASS:
            if (wrk->objcore != NULL)
                wrk->objcore->flags |= OC_F_PASS;
            sp->step = STP_FETCHBODY;
            return (0);
        case VCL_RET_DELIVER:
            AssertObjCorePassOrBusy(wrk->objcore);
            sp->step = STP_FETCHBODY;
            return (0);
        default:
            break;
        }

        /* We are not going to fetch the body, Close the connection */
        VDI_CloseFd(wrk, &wrk->busyobj->vbc);
    }

    /* Clean up partial fetch */
    AZ(wrk->busyobj->vbc);

    if (wrk->objcore != NULL) {
        CHECK_OBJ_NOTNULL(wrk->objcore, OBJCORE_MAGIC);
        AZ(HSH_Deref(wrk, wrk->objcore, NULL));
        wrk->objcore = NULL;
    }
    VBO_DerefBusyObj(wrk, &wrk->busyobj);
    sp->director = NULL;
    wrk->storage_hint = NULL;

    switch (sp->handling) {
    case VCL_RET_RESTART:
        sp->restarts++;
        sp->step = STP_RECV;
        return (0);
    case VCL_RET_ERROR:
        sp->step = STP_ERROR;
        return (0);
    default:
        WRONG("Illegal action in vcl_fetch{}");
    }
}
Exemplo n.º 13
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);
}
Exemplo n.º 14
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);
}
Exemplo n.º 15
0
static int
cnt_miss(struct sess *sp)
{
    struct worker *wrk;

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

    AZ(wrk->obj);
    AN(wrk->objcore);
    CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);
    WS_Reset(wrk->ws, NULL);
    wrk->busyobj = VBO_GetBusyObj(wrk);
    http_Setup(wrk->busyobj->bereq, wrk->ws);
    http_FilterHeader(sp, HTTPH_R_FETCH);
    http_ForceGet(wrk->busyobj->bereq);
    if (cache_param->http_gzip_support) {
        /*
         * We always ask the backend for gzip, even if the
         * client doesn't grok it.  We will uncompress for
         * the minority of clients which don't.
         */
        http_Unset(wrk->busyobj->bereq, H_Accept_Encoding);
        http_SetHeader(wrk, sp->vsl_id, wrk->busyobj->bereq,
                       "Accept-Encoding: gzip");
    }
    wrk->connect_timeout = 0;
    wrk->first_byte_timeout = 0;
    wrk->between_bytes_timeout = 0;

    VCL_miss_method(sp);

    switch(sp->handling) {
    case VCL_RET_ERROR:
        AZ(HSH_Deref(wrk, wrk->objcore, NULL));
        wrk->objcore = NULL;
        http_Setup(wrk->busyobj->bereq, NULL);
        VBO_DerefBusyObj(wrk, &wrk->busyobj);
        sp->step = STP_ERROR;
        return (0);
    case VCL_RET_PASS:
        AZ(HSH_Deref(wrk, wrk->objcore, NULL));
        wrk->objcore = NULL;
        VBO_DerefBusyObj(wrk, &wrk->busyobj);
        sp->step = STP_PASS;
        return (0);
    case VCL_RET_FETCH:
        CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);
        sp->step = STP_FETCH;
        return (0);
    case VCL_RET_RESTART:
        AZ(HSH_Deref(wrk, wrk->objcore, NULL));
        wrk->objcore = NULL;
        VBO_DerefBusyObj(wrk, &wrk->busyobj);
        INCOMPL();
    default:
        WRONG("Illegal action in vcl_miss{}");
    }
}