/** 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; }