VCL_VOID VRT_l_beresp_storage_hint(VRT_CTX, const char *str, ...) { const char *p; va_list ap; uintptr_t sn; VCL_STEVEDORE stv; CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC); sn = WS_Snapshot(ctx->ws); va_start(ap, str); p = VRT_String(ctx->ws, NULL, str, ap); va_end(ap); if (p == NULL) { VSLb(ctx->vsl, SLT_LostHeader, "storage_hint"); WS_Reset(ctx->ws, sn); WS_MarkOverflow(ctx->ws); return; } stv = VRT_stevedore(p); if (stv != NULL) ctx->bo->storage = stv; WS_Reset(ctx->ws, sn); }
/*-------------------------------------------------------------------- * The very first request */ static int cnt_first(struct sess *sp) { /* * XXX: If we don't have acceptfilters we are somewhat subject * XXX: to DoS'ing here. One remedy would be to set a shorter * XXX: SO_RCVTIMEO and once we have received something here * XXX: increase it to the normal value. */ assert(sp->xid == 0); assert(sp->restarts == 0); VCA_Prep(sp); /* Record the session watermark */ sp->ws_ses = WS_Snapshot(sp->ws); /* Receive a HTTP protocol request */ HTC_Init(sp->htc, sp->ws, sp->fd); sp->wrk->lastused = sp->t_open; sp->acct_req.sess++; sp->step = STP_WAIT; return (0); }
static int cnt_first(struct sess *sp) { struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); /* * XXX: If we don't have acceptfilters we are somewhat subject * XXX: to DoS'ing here. One remedy would be to set a shorter * XXX: SO_RCVTIMEO and once we have received something here * XXX: increase it to the normal value. */ assert(sp->xid == 0); assert(sp->restarts == 0); AZ(sp->esi_level); VCA_Prep(sp); /* Record the session watermark */ sp->ws_ses = WS_Snapshot(sp->ws); /* Receive a HTTP protocol request */ HTC_Init(sp->htc, sp->ws, sp->fd, sp->vsl_id, cache_param->http_req_size, cache_param->http_req_hdr_len); wrk->acct_tmp.sess++; sp->step = STP_WAIT; return (0); }
vmod_log(VRT_CTX, const char *fmt, ...) { const char *p; va_list ap; uintptr_t sn; CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); sn = WS_Snapshot(ctx->ws); va_start(ap, fmt); p = VRT_String(ctx->ws, NULL, fmt, ap); va_end(ap); if (p == NULL) { WS_MarkOverflow(ctx->ws); WS_Reset(ctx->ws, sn); return; } AN(p); if (ctx->vsl != NULL) VSLb(ctx->vsl, SLT_VCL_Log, "%s", p); else VSL(SLT_VCL_Log, 0, "%s", p); WS_Reset(ctx->ws, sn); }
static void vcl_call_method(struct worker *wrk, struct req *req, struct busyobj *bo, void *specific, unsigned method, vcl_func_f *func) { uintptr_t aws; struct vrt_ctx ctx; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); INIT_OBJ(&ctx, VRT_CTX_MAGIC); if (req != NULL) { CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(req->vcl, VCL_MAGIC); VCL_Req2Ctx(&ctx, req); } if (bo != NULL) { if (req) assert(method == VCL_MET_PIPE); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CHECK_OBJ_NOTNULL(bo->vcl, VCL_MAGIC); VCL_Bo2Ctx(&ctx, bo); } assert(ctx.now != 0); ctx.syntax = ctx.vcl->conf->syntax; ctx.specific = specific; ctx.method = method; wrk->handling = 0; ctx.handling = &wrk->handling; aws = WS_Snapshot(wrk->aws); wrk->cur_method = method; wrk->seen_methods |= method; AN(ctx.vsl); VSLb(ctx.vsl, SLT_VCL_call, "%s", VCL_Method_Name(method)); func(&ctx); VSLb(ctx.vsl, SLT_VCL_return, "%s", VCL_Return_Name(wrk->handling)); wrk->cur_method |= 1; // Magic marker if (wrk->handling == VCL_RET_FAIL) wrk->stats->vcl_fail++; /* * VCL/Vmods are not allowed to make permanent allocations from * wrk->aws, but they can reserve and return from it. */ assert(aws == WS_Snapshot(wrk->aws)); }
void vmod_workspace_snap(VRT_CTX, VCL_ENUM which) { struct ws *ws; CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); ws = wsfind(ctx, which); WS_Assert(ws); debug_ws_snap = WS_Snapshot(ws); }
static enum fetch_step vbf_stp_mkbereq(struct worker *wrk, struct busyobj *bo) { const char *q; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CHECK_OBJ_NOTNULL(bo->req, REQ_MAGIC); assert(bo->fetch_objcore->boc->state == BOS_INVALID); AZ(bo->storage); HTTP_Setup(bo->bereq0, bo->ws, bo->vsl, SLT_BereqMethod); http_FilterReq(bo->bereq0, bo->req->http, bo->do_pass ? HTTPH_R_PASS : HTTPH_R_FETCH); if (!bo->do_pass) { http_ForceField(bo->bereq0, HTTP_HDR_METHOD, "GET"); http_ForceField(bo->bereq0, HTTP_HDR_PROTO, "HTTP/1.1"); if (cache_param->http_gzip_support) http_ForceHeader(bo->bereq0, H_Accept_Encoding, "gzip"); } else { AZ(bo->stale_oc); if (bo->bereq0->protover > 11) http_ForceField(bo->bereq0, HTTP_HDR_PROTO, "HTTP/1.1"); } http_CopyHome(bo->bereq0); if (bo->stale_oc != NULL && ObjCheckFlag(bo->wrk, bo->stale_oc, OF_IMSCAND) && (bo->stale_oc->boc != NULL || ObjGetLen(wrk, bo->stale_oc) != 0)) { AZ(bo->stale_oc->flags & OC_F_PASS); q = HTTP_GetHdrPack(bo->wrk, bo->stale_oc, H_Last_Modified); if (q != NULL) http_PrintfHeader(bo->bereq0, "If-Modified-Since: %s", q); q = HTTP_GetHdrPack(bo->wrk, bo->stale_oc, H_ETag); if (q != NULL) http_PrintfHeader(bo->bereq0, "If-None-Match: %s", q); } HTTP_Setup(bo->bereq, bo->ws, bo->vsl, SLT_BereqMethod); bo->ws_bo = WS_Snapshot(bo->ws); HTTP_Copy(bo->bereq, bo->bereq0); if (bo->req->req_body_status == REQ_BODY_NONE) { bo->req = NULL; ObjSetState(bo->wrk, bo->fetch_objcore, BOS_REQ_DONE); } return (F_STP_STARTFETCH); }
vmod_syslog(VRT_CTX, VCL_INT fac, const char *fmt, ...) { const char *p; va_list ap; uintptr_t sn; CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); sn = WS_Snapshot(ctx->ws); va_start(ap, fmt); p = VRT_String(ctx->ws, NULL, fmt, ap); va_end(ap); if (p != NULL) syslog((int)fac, "%s", p); WS_Reset(ctx->ws, sn); }
static enum fetch_step vbf_stp_mkbereq(const struct worker *wrk, struct busyobj *bo) { const char *q; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CHECK_OBJ_NOTNULL(bo->req, REQ_MAGIC); assert(bo->state == BOS_INVALID); AZ(bo->storage_hint); HTTP_Setup(bo->bereq0, bo->ws, bo->vsl, SLT_BereqMethod); http_FilterReq(bo->bereq0, bo->req->http, bo->do_pass ? HTTPH_R_PASS : HTTPH_R_FETCH); if (!bo->do_pass) { http_ForceField(bo->bereq0, HTTP_HDR_METHOD, "GET"); http_ForceField(bo->bereq0, HTTP_HDR_PROTO, "HTTP/1.1"); if (cache_param->http_gzip_support) http_ForceHeader(bo->bereq0, H_Accept_Encoding, "gzip"); AN(bo->req); bo->req = NULL; http_CopyHome(bo->bereq0); } else AZ(bo->stale_oc); if (bo->stale_oc != NULL) { q = HTTP_GetHdrPack(bo->wrk, bo->stale_oc, H_Last_Modified); if (q != NULL) http_PrintfHeader(bo->bereq0, "If-Modified-Since: %s", q); q = HTTP_GetHdrPack(bo->wrk, bo->stale_oc, H_ETag); if (q != NULL) http_PrintfHeader(bo->bereq0, "If-None-Match: %s", q); } HTTP_Setup(bo->bereq, bo->ws, bo->vsl, SLT_BereqMethod); bo->ws_bo = WS_Snapshot(bo->ws); HTTP_Copy(bo->bereq, bo->bereq0); VBO_setstate(bo, BOS_REQ_DONE); return (F_STP_STARTFETCH); }
void V1L_Reserve(struct worker *wrk, struct ws *ws, int *fd, struct vsl_log *vsl, double t0) { struct v1l *v1l; unsigned u; void *res; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); AZ(wrk->v1l); if (WS_Overflowed(ws)) return; res = WS_Snapshot(ws); v1l = WS_Alloc(ws, sizeof *v1l); if (v1l == NULL) return; INIT_OBJ(v1l, V1L_MAGIC); v1l->ws = ws; v1l->res = res; u = WS_Reserve(ws, 0); u = PRNDDN(u); u /= sizeof(struct iovec); if (u == 0) { WS_Release(ws, 0); WS_MarkOverflow(ws); return; } else if (u > IOV_MAX) u = IOV_MAX; v1l->iov = (void*)PRNDUP(ws->f); v1l->siov = u; v1l->ciov = u; v1l->werr = 0; v1l->liov = 0; v1l->niov = 0; v1l->wfd = fd; v1l->t0 = t0; v1l->vsl = vsl; wrk->v1l = v1l; }
static void ved_include(struct req *preq, const char *src, const char *host, struct ecx *ecx) { struct worker *wrk; struct req *req; enum req_fsm_nxt s; struct transport xp; CHECK_OBJ_NOTNULL(preq, REQ_MAGIC); CHECK_OBJ_NOTNULL(ecx, ECX_MAGIC); wrk = preq->wrk; if (preq->esi_level >= cache_param->max_esi_depth) return; req = Req_New(wrk, preq->sp); req->req_body_status = REQ_BODY_NONE; AZ(req->vsl->wid); req->vsl->wid = VXID_Get(wrk, VSL_CLIENTMARKER); VSLb(req->vsl, SLT_Begin, "req %u esi", VXID(preq->vsl->wid)); VSLb(preq->vsl, SLT_Link, "req %u esi", VXID(req->vsl->wid)); req->esi_level = preq->esi_level + 1; if (preq->esi_level == 0) assert(preq->top == preq); else CHECK_OBJ_NOTNULL(preq->top, REQ_MAGIC); req->top = preq->top; HTTP_Copy(req->http0, preq->http0); req->http0->ws = req->ws; req->http0->vsl = req->vsl; req->http0->logtag = SLT_ReqMethod; req->http0->conds = 0; http_SetH(req->http0, HTTP_HDR_URL, src); if (host != NULL && *host != '\0') { http_Unset(req->http0, H_Host); http_SetHeader(req->http0, host); } http_ForceField(req->http0, HTTP_HDR_METHOD, "GET"); http_ForceField(req->http0, HTTP_HDR_PROTO, "HTTP/1.1"); /* Don't allow conditionalss, we can't use a 304 */ http_Unset(req->http0, H_If_Modified_Since); http_Unset(req->http0, H_If_None_Match); /* Don't allow Range */ http_Unset(req->http0, H_Range); /* Set Accept-Encoding according to what we want */ http_Unset(req->http0, H_Accept_Encoding); if (ecx->isgzip) http_ForceHeader(req->http0, H_Accept_Encoding, "gzip"); /* Client content already taken care of */ http_Unset(req->http0, H_Content_Length); /* Reset request to status before we started messing with it */ HTTP_Copy(req->http, req->http0); req->vcl = preq->vcl; preq->vcl = NULL; req->wrk = preq->wrk; /* * XXX: We should decide if we should cache the director * XXX: or not (for session/backend coupling). Until then * XXX: make sure we don't trip up the check in vcl_recv. */ req->req_step = R_STP_RECV; req->t_req = preq->t_req; assert(isnan(req->t_first)); assert(isnan(req->t_prev)); INIT_OBJ(&xp, TRANSPORT_MAGIC); xp.deliver = VED_Deliver; req->transport = &xp; req->transport_priv = ecx; THR_SetRequest(req); VSLb_ts_req(req, "Start", W_TIM_real(wrk)); req->ws_req = WS_Snapshot(req->ws); while (1) { req->wrk = wrk; s = CNT_Request(wrk, req); if (s == REQ_FSM_DONE) break; DSL(DBG_WAITINGLIST, req->vsl->wid, "loop waiting for ESI (%d)", (int)s); assert(s == REQ_FSM_DISEMBARK); AZ(req->wrk); (void)usleep(10000); } VRTPRIV_dynamic_kill(req->sp->privs, (uintptr_t)req); CNT_AcctLogCharge(wrk->stats, req); VSL_End(req->vsl); preq->vcl = req->vcl; req->vcl = NULL; req->wrk = NULL; THR_SetRequest(preq); Req_Release(req); }
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); }
static int http1_dissect(struct worker *wrk, struct req *req) { const char *r_100 = "HTTP/1.1 100 Continue\r\n\r\n"; const char *r_400 = "HTTP/1.1 400 Bad Request\r\n\r\n"; const char *r_417 = "HTTP/1.1 417 Expectation Failed\r\n\r\n"; const char *p; ssize_t r; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); /* Allocate a new vxid now that we know we'll need it. */ AZ(req->vsl->wid); req->vsl->wid = VXID_Get(wrk, VSL_CLIENTMARKER); VSLb(req->vsl, SLT_Begin, "req %u rxreq", VXID(req->sp->vxid)); VSL(SLT_Link, req->sp->vxid, "req %u rxreq", VXID(req->vsl->wid)); AZ(isnan(req->t_first)); /* First byte timestamp set by http1_wait */ AZ(isnan(req->t_req)); /* Complete req rcvd set by http1_wait */ req->t_prev = req->t_first; VSLb_ts_req(req, "Start", req->t_first); VSLb_ts_req(req, "Req", req->t_req); /* Borrow VCL reference from worker thread */ VCL_Refresh(&wrk->vcl); req->vcl = wrk->vcl; wrk->vcl = NULL; HTTP_Setup(req->http, req->ws, req->vsl, SLT_ReqMethod); req->err_code = HTTP1_DissectRequest(req->htc, req->http); /* If we could not even parse the request, just close */ if (req->err_code != 0) { VSLb(req->vsl, SLT_HttpGarbage, "%.*s", (int)(req->htc->rxbuf_e - req->htc->rxbuf_b), req->htc->rxbuf_b); wrk->stats->client_req_400++; r = write(req->sp->fd, r_400, strlen(r_400)); if (r > 0) req->acct.resp_hdrbytes += r; req->doclose = SC_RX_JUNK; return (-1); } assert (req->req_body_status == REQ_BODY_INIT); if (req->htc->body_status == BS_CHUNKED) { req->req_body_status = REQ_BODY_WITHOUT_LEN; } else if (req->htc->body_status == BS_LENGTH) { req->req_body_status = REQ_BODY_WITH_LEN; } else if (req->htc->body_status == BS_NONE) { req->req_body_status = REQ_BODY_NONE; } else if (req->htc->body_status == BS_EOF) { req->req_body_status = REQ_BODY_WITHOUT_LEN; } else { WRONG("Unknown req.body_length situation"); } if (http_GetHdr(req->http, H_Expect, &p)) { if (strcasecmp(p, "100-continue")) { wrk->stats->client_req_417++; req->err_code = 417; r = write(req->sp->fd, r_417, strlen(r_417)); if (r > 0) req->acct.resp_hdrbytes += r; req->doclose = SC_RX_JUNK; return (-1); } r = write(req->sp->fd, r_100, strlen(r_100)); if (r > 0) req->acct.resp_hdrbytes += r; if (r != strlen(r_100)) { req->doclose = SC_REM_CLOSE; return (-1); } http_Unset(req->http, H_Expect); } wrk->stats->client_req++; wrk->stats->s_req++; AZ(req->err_code); req->ws_req = WS_Snapshot(req->ws); req->doclose = http_DoConnection(req->http); if (req->doclose == SC_RX_BAD) { r = write(req->sp->fd, r_400, strlen(r_400)); if (r > 0) req->acct.resp_hdrbytes += r; return (-1); } assert(req->req_body_status != REQ_BODY_INIT); HTTP_Copy(req->http0, req->http); // For ESI & restart return (0); }
static const char * sort_querystring(struct ws *ws, const char *uri) { if (uri == NULL) { return NULL; } char *query_string = strchr(uri, '?'); if (query_string == NULL) { return uri; } if (query_string[1] == '\0') { return truncate_querystring(ws, uri, query_string); } /* reserve some memory */ char *snapshot = WS_Snapshot(ws); char *sorted_uri = WS_Alloc(ws, strlen(uri) + 1); WS_Assert(ws); if (sorted_uri == NULL) { WS_Reset(ws, snapshot); return uri; } unsigned available = WS_Reserve(ws, 0); struct query_param *params = (struct query_param*) ws->f; struct query_param *end = params + available; /* initialize the params array */ int head = 10; if (¶ms[head + 1] > end) { head = 0; } if (¶ms[head + 1] > end) { WS_Release(ws, 0); WS_Reset(ws, snapshot); return uri; } int tail = head; int last_param = head; /* search and sort params */ bool sorted = true; char *c = query_string + 1; params[head].value = c; for (; *c != '\0' && ¶ms[tail+1] < end; c++) { if (*c != '&') { continue; } const char *current_param = c+1; params[last_param].length = c - params[last_param].value; if (head > 0 && compare_params(params[head].value, current_param) > -1) { sorted = false; params[--head].value = current_param; last_param = head; continue; } if (compare_params(params[tail].value, current_param) < 1) { params[++tail].value = current_param; last_param = tail; continue; } sorted = false; int i = tail++; params[tail] = params[i]; int previous = i-1; while (i > head && compare_params(params[previous].value, current_param) > -1) { params[i--] = params[previous--]; } params[i].value = current_param; last_param = i; } if (sorted == true || ¶ms[tail+1] >= end || tail - head < 1) { WS_Release(ws, 0); WS_Reset(ws, snapshot); return uri; } params[last_param].length = c - params[last_param].value; /* copy the url parts */ char *position = mempcpy(sorted_uri, uri, query_string - uri + 1); int count = tail-head; for (;count > 0; count--, ++head) { if (params[head].length > 0) { position = mempcpy(position, params[head].value, params[head].length); *position++ = '&'; } } if (params[head].length > 0) { position = mempcpy(position, params[head].value, params[head].length); } else { position--; } *position = '\0'; WS_Release(ws, 0); return sorted_uri; }