double http_GetHdrQ(const struct http *hp, const char *hdr, const char *field) { char *h; int i; double a, b; h = NULL; i = http_GetHdrData(hp, hdr, field, &h); if (!i) return (0.); if (h == NULL) return (1.); /* Skip whitespace, looking for '=' */ while (*h && vct_issp(*h)) h++; if (*h++ != ';') return (1.); while (*h && vct_issp(*h)) h++; if (*h++ != 'q') return (1.); while (*h && vct_issp(*h)) h++; if (*h++ != '=') return (1.); while (*h && vct_issp(*h)) h++; a = 0.; while (vct_isdigit(*h)) { a *= 10.; a += *h - '0'; h++; } if (*h++ != '.') return (a); b = .1; while (vct_isdigit(*h)) { a += b * (*h - '0'); b *= .1; h++; } return (a); }
uint16_t http_DissectResponse(struct worker *w, const struct http_conn *htc, struct http *hp) { int j; uint16_t retval = 0; char *p; CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC); hp->logtag = HTTP_Rx; if (http_splitline(w, htc->fd, hp, htc, HTTP_HDR_PROTO, HTTP_HDR_STATUS, HTTP_HDR_RESPONSE)) retval = 503; if (retval == 0 && memcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.", 7)) retval = 503; if (retval == 0 && Tlen(hp->hd[HTTP_HDR_STATUS]) != 3) retval = 503; if (retval == 0) { hp->status = 0; p = hp->hd[HTTP_HDR_STATUS].b; for (j = 100; j != 0; j /= 10) { if (!vct_isdigit(*p)) { retval = 503; break; } hp->status += (uint16_t)(j * (*p - '0')); p++; } if (*p != '\0') retval = 503; } if (retval != 0) { WSLR(w, SLT_HttpGarbage, htc->fd, htc->rxbuf); assert(retval >= 100 && retval <= 999); hp->status = retval; } else { http_ProtoVer(hp); } if (hp->hd[HTTP_HDR_RESPONSE].b == NULL || !Tlen(hp->hd[HTTP_HDR_RESPONSE])) { /* Backend didn't send a response string, use the standard */ hp->hd[HTTP_HDR_RESPONSE].b = TRUST_ME(http_StatusMessage(hp->status)); hp->hd[HTTP_HDR_RESPONSE].e = strchr(hp->hd[HTTP_HDR_RESPONSE].b, '\0'); } return (retval); }
static void v1d_dorange(struct req *req, const char *r) { ssize_t low, high, has_low; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); assert(req->obj->response == 200); if (strncmp(r, "bytes=", 6)) return; r += 6; /* The low end of range */ has_low = low = 0; if (!vct_isdigit(*r) && *r != '-') return; while (vct_isdigit(*r)) { has_low = 1; low *= 10; low += *r - '0'; r++; } if (low >= req->obj->len) return; if (*r != '-') return; r++; /* The high end of range */ if (vct_isdigit(*r)) { high = 0; while (vct_isdigit(*r)) { high *= 10; high += *r - '0'; r++; } if (!has_low) { low = req->obj->len - high; if (low < 0) low = 0; high = req->obj->len - 1; } } else high = req->obj->len - 1; if (*r != '\0') return; if (high >= req->obj->len) high = req->obj->len - 1; if (low > high) return; http_PrintfHeader(req->resp, "Content-Range: bytes %jd-%jd/%jd", (intmax_t)low, (intmax_t)high, (intmax_t)req->obj->len); http_Unset(req->resp, H_Content_Length); if (req->res_mode & RES_LEN) http_PrintfHeader(req->resp, "Content-Length: %jd", (intmax_t)(1 + high - low)); http_SetResp(req->resp, "HTTP/1.1", 206, "Partial Content"); req->range_off = 0; req->range_low = low; req->range_high = high + 1; VDP_push(req, v1d_range_bytes); }