Example #1
0
/** Parse individual header field (name-value pair) */
APT_DECLARE(apt_header_field_t*) apt_header_field_parse(apt_text_stream_t *stream, apr_pool_t *pool)
{
	apr_size_t folding_length = 0;
	apr_array_header_t *folded_lines = NULL;
	apt_header_field_t *header_field;
	apt_str_t temp_line;
	apt_str_t *line;
	apt_pair_t pair;
	/* read name-value pair */
	if(apt_text_header_read(stream,&pair) == FALSE) {
		return NULL;
	}

	/* check folding lines (value spanning multiple lines) */
	while(stream->pos < stream->end) {
		if(apt_text_is_wsp(*stream->pos) == FALSE) {
			break;
		}

		stream->pos++;

		/* skip further white spaces (if any) */
		apt_text_white_spaces_skip(stream);

		if(!folded_lines) {
			folded_lines = apr_array_make(pool,1,sizeof(apt_str_t));
		}
		if(apt_text_line_read(stream,&temp_line) == TRUE) {
			line = apr_array_push(folded_lines);
			*line = temp_line;
			folding_length += line->length;
		}
	};

	header_field = apt_header_field_alloc(pool);
	/* copy parsed name of the header field */
	header_field->name.length = pair.name.length;
	header_field->name.buf = apr_palloc(pool, pair.name.length + 1);
	if(pair.name.length) {
		memcpy(header_field->name.buf, pair.name.buf, pair.name.length);
	}
	header_field->name.buf[header_field->name.length] = '\0';

	/* copy parsed value of the header field */
	header_field->value.length = pair.value.length + folding_length;
	header_field->value.buf = apr_palloc(pool, header_field->value.length + 1);
	if(pair.value.length) {
		memcpy(header_field->value.buf, pair.value.buf, pair.value.length);
	}

	if(folding_length) {
		int i;
		char *pos = header_field->value.buf + pair.value.length;
		/* copy parsed folding lines */
		for(i=0; i<folded_lines->nelts; i++) {
			line = &APR_ARRAY_IDX(folded_lines,i,apt_str_t);

			memcpy(pos,line->buf,line->length);
			pos += line->length;
		}
	}
	header_field->value.buf[header_field->value.length] = '\0';

	return header_field;
}
/** To be used to navigate through the header fields (name:value pairs) of the text stream (message) 
	Valid header fields are:
		name:value<CRLF>
		name: value<CRLF>
		name:    value<CRLF>
		name: value<LF>
		name:<CRLF>              (only name, no value)
		<CRLF>                   (empty header)
	Malformed header fields are:
		name:value               (missing end of line <CRLF>)
		name<CRLF>               (missing separator ':')
*/
APT_DECLARE(apt_bool_t) apt_text_header_read(apt_text_stream_t *stream, apt_pair_t *pair)
{
	char *pos = stream->pos;
	apt_bool_t status = FALSE;
	apt_string_reset(&pair->name);
	apt_string_reset(&pair->value);
	/* while not end of stream */
	while(pos < stream->end) {
		if(*pos == APT_TOKEN_CR) {
			/* end of line detected */
			if(pair->value.buf) {
				/* set length of the value */
				pair->value.length = pos - pair->value.buf;
			}
			pos++;
			if(pos < stream->end && *pos == APT_TOKEN_LF) {
				pos++;
			}
			status = TRUE;
			break;
		}
		else if(*pos == APT_TOKEN_LF) {
			/* end of line detected */
			if(pair->value.buf) {
				/* set length of the value */
				pair->value.length = pos - pair->value.buf;
			}
			pos++;
			status = TRUE;
			break;
		}
		else if(!pair->name.length) {
			/* skip preceding white spaces (SHOULD NOT be any WSP, though) and read name */
			if(!pair->name.buf && apt_text_is_wsp(*pos) == FALSE) {
				pair->name.buf = pos;
			}
			if(*pos == ':') {
				/* set length of the name */
				pair->name.length = pos - pair->name.buf;
			}
		}
		else if(!pair->value.length) {
			/* skip preceding white spaces and read value */
			if(!pair->value.buf && apt_text_is_wsp(*pos) == FALSE) {
				pair->value.buf = pos;
			}
		}
		pos++;
	}

	if(status == TRUE) {
		/* advance stream pos regardless it's a valid header or not */
		stream->pos = pos;
		
		/* if length == 0 && buf => header is malformed */
		if(!pair->name.length && pair->name.buf) {
			status = FALSE;
		}
	}
	else {
		/* end of stream is reached, do not advance stream pos, but set is_eos flag */
		stream->is_eos = TRUE;
	}

	return status;
}