Beispiel #1
0
/**
 * Add compound piece to @str and return pointer to the piece.
 */
TfwStr *
tfw_str_add_compound(TfwPool *pool, TfwStr *str)
{
	/* Need to specify exact string duplicate to grow. */
	BUG_ON(TFW_STR_DUP(str));

	return __str_grow_tree(pool, str, __TFW_STR_COMPOUND, 1);
}
Beispiel #2
0
/**
 * 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);
	}
Beispiel #3
0
int
tfw_strcat(TfwPool *pool, TfwStr *dst, TfwStr *src)
{
	int n = TFW_STR_CHUNKN(src);
	TfwStr *to, *c, *end;

	BUG_ON(TFW_STR_DUP(dst));
	BUG_ON(TFW_STR_DUP(src));

	to = __str_grow_tree(pool, dst, __TFW_STR_COMPOUND, n ? : 1);
	if (!to)
		return -ENOMEM;

	n = 0;
	TFW_STR_FOR_EACH_CHUNK(c, src, end) {
		n += c->len;
		to->ptr = c->ptr;
		to->len = c->len;
		to->skb = c->skb;
		++to;
	}
Beispiel #4
0
/**
 * 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);
	});
Beispiel #5
0
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));
}
Beispiel #6
0
int
tfw_strcpy(TfwStr *dst, const TfwStr *src)
{
	int n1, n2, o1 = 0, o2 = 0, chunks = 0;
	int mode = (TFW_STR_PLAIN(src) << 1) | TFW_STR_PLAIN(dst);
	TfwStr *c1, *c2, *end;

	BUG_ON(TFW_STR_DUP(dst));
	BUG_ON(TFW_STR_DUP(src));

	/* After the check we don't need to control @dst chunks overrun. */
	if (unlikely(src->len > dst->len))
		return -E2BIG;

	switch (mode) {
	case 3: /* The both are plain. */
		memcpy(dst->ptr, src->ptr, min(src->len, dst->len));
		break;
	case 1: /* @src is compound, @dst is plain. */
		n1 = TFW_STR_CHUNKN(src);
		end = (TfwStr *)src->ptr + n1;
		for (c1 = (TfwStr *)src->ptr; c1 < end; ++c1) {
			memcpy((char *)dst->ptr + o2, c1->ptr, c1->len);
			o2 += c1->len;
		}
		BUG_ON(o2 != src->len);
		break;
	case 2: /* @src is plain, @dst is compound. */
		for (c2 = (TfwStr *)dst->ptr; o1 < src->len; ++c2) {
			/* Update length of the last chunk. */
			c2->len = min(c2->len, src->len - o1);
			memcpy(c2->ptr, (char *)src->ptr + o1, c2->len);
			++chunks;
			o1 += c2->len;
		}
		break;
	case 0: /* The both are compound. */
		n1 = TFW_STR_CHUNKN(src);
		n2 = TFW_STR_CHUNKN(dst);
		c1 = (TfwStr *)src->ptr;
		c2 = (TfwStr *)dst->ptr;
		end = c1 + n1 - 1;
		while (1) {
			int _n = min(c1->len - o1, c2->len - o2);
			memcpy((char *)c2->ptr + o2, (char *)c1->ptr + o1, _n);
			if (c1 == end && _n == c1->len - o1) {
				/* Adjust @dst last chunk length. */
				c2->len = o2 + _n;
				++chunks;
				break;
			}
			if (c1->len - o1 == c2->len - o2) {
				++c1;
				++c2;
				++chunks;
				o1 = o2 = 0;
			}
			else if (_n == c1->len - o1) {
				++c1;
				o1 = 0;
				o2 += _n;
			}
			else {
				++c2;
				++chunks;
				o2 = 0;
				o1 += _n;
			}
		}
	}

	/* Set resulting number of chunks, forget about others. */
	__TFW_STR_CHUNKN_SET(dst, chunks);
	dst->len = src->len;

	return 0;
}