/** * Fills @val with second part of special HTTP header containing the header * value. */ void tfw_http_msg_hdr_val(TfwStr *hdr, unsigned id, TfwStr *val) { static const size_t hdr_lens[] = { [TFW_HTTP_HDR_HOST] = sizeof("Host:") - 1, [TFW_HTTP_HDR_CONTENT_LENGTH] = sizeof("Content-Length:") - 1, [TFW_HTTP_HDR_CONTENT_TYPE] = sizeof("Content-Type:") - 1, [TFW_HTTP_HDR_CONNECTION] = sizeof("Connection:") - 1, [TFW_HTTP_HDR_X_FORWARDED_FOR] = sizeof("X-Forwarded-For:") - 1, [TFW_HTTP_HDR_USER_AGENT] = sizeof("User-Agent:") - 1, [TFW_HTTP_HDR_COOKIE] = sizeof("Cookie:") - 1, }; TfwStr *c, *end; int nlen = hdr_lens[id]; BUG_ON(TFW_STR_DUP(hdr)); BUG_ON(id >= TFW_HTTP_HDR_RAW); /* Only Host: header is allowed to be empty * If header string is plain, it is always empty header. * Not empty headers are compount strings. */ BUG_ON(id == TFW_HTTP_HDR_HOST ? (nlen > hdr->len) : (nlen >= hdr->len || TFW_STR_PLAIN(hdr))); *val = *hdr; /* Field value, if it exist, lies in the separate chunk. * So we skip several first chunks, containing field name, * to get the field value. If we have field with empty value, * we get an empty string with val->len = 0 and val->ptr from the * last name's chunk, but it is unimportant. */ TFW_STR_FOR_EACH_CHUNK(c, hdr, end) { BUG_ON(!c->len); if (nlen > 0) { nlen -= c->len; val->len -= c->len; } else if (unlikely(((char *)c->ptr)[0] == ' ' || ((char *)c->ptr)[0] == '\t')) { /* * RFC 7230: skip OWS before header field. * In most cases OWS is on the same chunk with * the header name. * Header field-value always begins at new chunk. */ val->len -= c->len; } else { break; } TFW_STR_CHUNKN_SUB(val, 1); }
/** * Fills @val with second part of specula HTTP header containing the header * value. */ void tfw_http_msg_hdr_val(TfwStr *hdr, int id, TfwStr *val) { static const size_t hdr_lens[] = { [TFW_HTTP_HDR_HOST] = sizeof("Host:") - 1, [TFW_HTTP_HDR_CONTENT_LENGTH] = sizeof("Content-Length:") - 1, [TFW_HTTP_HDR_CONNECTION] = sizeof("Connection:") - 1, [TFW_HTTP_HDR_X_FORWARDED_FOR] = sizeof("X-Forwarded-For:") - 1, }; TfwStr *c; int nlen = hdr_lens[id]; BUG_ON(TFW_STR_PLAIN(hdr)); BUG_ON(TFW_STR_DUP(hdr)); BUG_ON(nlen >= hdr->len); BUG_ON(id >= TFW_HTTP_HDR_RAW); *val = *hdr; val->len -= nlen; TFW_STR_FOR_EACH_CHUNK(c, hdr, { BUG_ON(!c->len); BUG_ON(c->len >= val->len); if (nlen > 0) { nlen -= val->len; } else if (unlikely(((char *)c->ptr)[0] == ' ' || ((char *)c->ptr)[0] == '\t')) { /* * RFC 7230: skip OWS before header field. * In most cases OWS is on the same chunk with * the header name. * Header field always begins at new chunk. */ val->len -= c->len; } else { break; } TFW_STR_CHUNKN_SUB(val, 1); });
void tfw_str_del_chunk(TfwStr *str, int id) { unsigned int cn = TFW_STR_CHUNKN(str); if (unlikely(TFW_STR_PLAIN(str))) return; BUG_ON(TFW_STR_DUP(str)); BUG_ON(id >= cn); if (TFW_STR_CHUNKN(str) == 2) { /* Just fall back to plain string. */ *str = *((TfwStr *)str->ptr + (id ^ 1)); return; } str->len -= TFW_STR_CHUNK(str, id)->len; TFW_STR_CHUNKN_SUB(str, 1); /* Move all chunks after @id. */ memmove((TfwStr *)str->ptr + id, (TfwStr *)str->ptr + id + 1, (cn - id - 1) * sizeof(TfwStr)); }