Esempio n. 1
0
/**
 * @return length of currently formatted header.
 */
size_t
header_fmt_length(const header_fmt_t *hf)
{
	header_fmt_check(hf);

	return str_len(hf->header);
}
Esempio n. 2
0
/**
 * Checks whether appending `len' bytes of data to the header would fit
 * within the maximum header size requirement in case a continuation
 * is emitted, and using the configured separator.
 */
bool
header_fmt_value_fits(const header_fmt_t *hf, size_t len)
{
	size_t final_len;
	size_t maxlen, n;

	header_fmt_check(hf);

	if (hf->empty)
		return FALSE;

	maxlen = size_saturate_sub(hf->max_size, sizeof("\r\n"));

	/*
	 * If it fits on the line, no continuation will have to be emitted.
	 * Otherwise, we'll need the stripped version of the separator,
	 * followed by "\r\n\t" (3 chars).
	 */

	final_len = size_saturate_add(str_len(hf->header), len);

	n = size_saturate_add(hf->current_len, size_saturate_add(len, hf->seplen));
	if (n <= hf->maxlen) {
		final_len = size_saturate_add(final_len, hf->seplen);
	} else {
		final_len = size_saturate_add(final_len, hf->stripped_seplen);
		final_len = size_saturate_add(final_len, 3);
	}

	return final_len < maxlen;	/* Could say "<=" perhaps, but let's be safe */
}
Esempio n. 3
0
/**
 * @return current header string.
 */
const char *
header_fmt_string(const header_fmt_t *hf)
{
	header_fmt_check(hf);

	return str_2c(hf->header);	/* Guaranteed to be always NUL-terminated */
}
Esempio n. 4
0
/**
 * Set max line length.
 */
void
header_fmt_set_line_length(header_fmt_t *hf, size_t maxlen)
{
	header_fmt_check(hf);
	g_assert(size_is_positive(maxlen));

	hf->maxlen = maxlen;
}
Esempio n. 5
0
/**
 * Append data `str' to the header line, atomically.
 *
 * Values are separated using the string specified at make time, if any.
 * If emitted before a continuation, the version with stripped trailing
 * whitespaces is used.
 *
 * To supersede the default separator, use header_fmt_append().
 *
 * @return TRUE if we were able to append the data whilst remaining under
 * the configured maximum length.
 */
bool
header_fmt_append_value(header_fmt_t *hf, const char *str)
{
	header_fmt_check(hf);
	g_assert(!hf->frozen);

	return header_fmt_append_full(hf,
		str, hf->sep, hf->seplen, hf->stripped_seplen);
}
Esempio n. 6
0
/**
 * Append data `str' to the header line, atomically.
 *
 * `separator' is an optional separator string that will be emitted BEFORE
 * outputting the data, and only when nothing has been emitted already.
 * Any trailing space will be stripped out of `separator' if emitting at the
 * end of a line.  It supersedes any separator configured at make time.
 *
 * To use the standard separator, use header_fmt_append_value().
 *
 * @return TRUE if we were able to append the data whilst remaining under
 * the configured maximum length.
 */
bool
header_fmt_append(header_fmt_t *hf, const char *str, const char *separator)
{
	size_t seplen;

	header_fmt_check(hf);
	g_assert(!hf->frozen);

	seplen = (separator == NULL) ? 0 : strlen(separator);

	return header_fmt_append_full(hf, str, separator, seplen, (size_t)-1);
}
Esempio n. 7
0
/**
 * Terminate header, emitting the trailing "\r\n".
 * Further appending is forbidden.
 */
void
header_fmt_end(header_fmt_t *hf)
{
	header_fmt_check(hf);
	g_assert(!hf->frozen);

	if (!hf->empty)
		STR_CAT(hf->header, "\r\n");
	hf->frozen = TRUE;

	g_assert(str_len(hf->header) < hf->max_size);
}
Esempio n. 8
0
/**
 * Convert current header to a string.
 *
 * @attention
 * NB: returns pointer to static data!
 */
const char *
header_fmt_to_string(const header_fmt_t *hf)
{
	static char line[HEADER_FMT_MAX_SIZE + 1];

	header_fmt_check(hf);

	if (str_len(hf->header) >= sizeof line) {
		g_warning("trying to format too long an HTTP line (%lu bytes)",
			(unsigned long) str_len(hf->header));
	}
	clamp_strncpy(line, sizeof line, str_2c(hf->header), str_len(hf->header));
	return line;
}
Esempio n. 9
0
/**
 * Dispose of header formatting context.
 */
void
header_fmt_free(header_fmt_t **hf_ptr)
{
	header_fmt_t *hf = *hf_ptr;

	if (hf) {
		header_fmt_check(hf);

		str_destroy_null(&hf->header);
		atom_str_free_null(&hf->sep);
		hf->magic = 0;
		WFREE(hf);
		*hf_ptr = NULL;
	}
}
Esempio n. 10
0
/**
 * Convert current header to a string.
 *
 * @attention
 * NB: returns pointer to static data!
 */
const char *
header_fmt_to_string(const header_fmt_t *hf)
{
	buf_t *b = buf_private(G_STRFUNC, HEADER_FMT_MAX_SIZE + 1);
	char *p = buf_data(b);
	size_t n = buf_size(b);

	header_fmt_check(hf);

	if (str_len(hf->header) >= n) {
		g_warning("trying to format too long an HTTP line (%zu bytes)",
			str_len(hf->header));
	}
	clamp_strncpy(p, n, str_2c(hf->header), str_len(hf->header));
	return p;
}
Esempio n. 11
0
/**
 * Create a new formatting context for a header line.
 *
 * @param `field' is the header field name, without trailing ':'.
 *
 * @param `separator' is the optional default separator to emit between
 * the values added via header_fmd_append_value().  To supersede the
 * default separator, use header_fmd_append() and specify another separator
 * explicitly.  If set to NULL, there will be no default separator and
 * values will be simply concatenated together.  The value given must
 * NOT be freed before the header_fmt_end() call (usually it will just
 * be a static string).  Trailing spaces in the separator will be stripped
 * if it is emitted at the end of a line before a continuation.
 *
 * @param `len_hint' is the expected line size, for pre-sizing purposes.
 * (0 to guess).
 *
 * @param `max_size' is the maximum header size, including the final "\r\n"
 * and the trailing NUL.  If the initial field name is larger than the
 * configured maximum size, the header field will remain completely empty.
 *
 * @return pointer to the formatting object.
 */
header_fmt_t *
header_fmt_make(const char *field, const char *separator,
	size_t len_hint, size_t max_size)
{
	struct header_fmt *hf;

	g_assert(size_is_non_negative(len_hint));

	WALLOC(hf);
	hf->magic = HEADER_FMT_MAGIC;
	hf->header = str_new(len_hint ? len_hint : HEADER_FMT_DFLT_LEN);
	hf->maxlen = HEADER_FMT_LINE_LEN;
	hf->data_emitted = FALSE;
	hf->frozen = FALSE;
	hf->max_size = max_size;
	hf->sep = atom_str_get(separator ? separator : "");
	hf->seplen = strlen(hf->sep);
	hf->stripped_seplen = stripped_strlen(hf->sep, hf->seplen);
	str_cat(hf->header, field);
	STR_CAT(hf->header, ": ");

	hf->current_len = str_len(hf->header);

	/*
	 * If right from the start the header would be larger than the configured
	 * size, force it to stay empty.  That means, the final string returned
	 * will be "", the empty string.
	 */

	if (str_len(hf->header) + sizeof("\r\n") > hf->max_size) {
		hf->empty = TRUE;
		str_setlen(hf->header, 0);
	} else {
		hf->empty = FALSE;
	}

	header_fmt_check(hf);

	return hf;
}
Esempio n. 12
0
/**
 * Append data `str' to the header line, atomically.
 *
 * @param `hf' no brief description.
 * @param `str' no brief description.
 * @param `separator' is an optional separator string that will be emitted
 *         BEFORE outputting the data, and only when nothing has been emitted
 *         already.
 * @param `slen' is the separator length, 0 if empty.
 * @param `sslen' is the stripped separator length, (size_t)-1 if unknown yet.
 *
 * @return TRUE if we were able to fit the string, FALSE if it would have
 * resulted in the header being larger than the configured max size (the
 * header line is left in the state it was in upon entry, in that case).
 */
static bool
header_fmt_append_full(header_fmt_t *hf, const char *str,
	const char *separator, size_t slen, size_t sslen)
{
	size_t len, curlen;
	gsize gslen;
	bool success;

	header_fmt_check(hf);
	g_assert(size_is_non_negative(slen));
	g_assert((size_t)-1 == sslen || size_is_non_negative(sslen));

	if (hf->empty)
		return FALSE;

	gslen = str_len(hf->header);
	len = strlen(str);
	curlen = hf->current_len;
	g_assert(size_is_non_negative(curlen));

	g_assert(len <= INT_MAX);	/* Legacy bug */

	if (
		size_saturate_add(curlen, size_saturate_add(len, slen)) >
			UNSIGNED(hf->maxlen)
	) {
		/*
		 * Emit sperator, if any and data was already emitted.
		 */

		if (separator != NULL && hf->data_emitted) {
			sslen = (size_t)-1 != sslen ? sslen :
				stripped_strlen(separator, slen);
			str_cat_len(hf->header, separator, sslen);
		}

		STR_CAT(hf->header, "\r\n\t");			/* Includes continuation */
		curlen = 1;								/* One tab */
	} else if (hf->data_emitted) {
		str_cat(hf->header, separator);
		curlen += slen;
	}

	str_cat(hf->header, str);

	/*
	 * Check for overflows, undoing string changes if needed.
	 */

	if (str_len(hf->header) + sizeof("\r\n") > hf->max_size) {
		success = FALSE;
		str_setlen(hf->header, gslen);			/* Undo! */
	} else {
		success = TRUE;
		hf->data_emitted = TRUE;
		hf->current_len = curlen + len;
	}

	g_assert(str_len(hf->header) + sizeof("\r\n") <= hf->max_size);

	return success;
}