aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmime
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rspamd.com>2023-11-25 13:42:03 +0000
committerVsevolod Stakhov <vsevolod@rspamd.com>2023-11-25 13:42:03 +0000
commite0befa616f7f0fdfc823b8a442f398e8c649cd95 (patch)
tree4bc1506a48b9703aa2643107a257ea67ab954553 /src/libmime
parentf8af1c1f2fea4c1c1eda945578eb8c16e7358ef3 (diff)
downloadrspamd-e0befa616f7f0fdfc823b8a442f398e8c649cd95.tar.gz
rspamd-e0befa616f7f0fdfc823b8a442f398e8c649cd95.zip
[Test] Add unit tests for unfolding
Diffstat (limited to 'src/libmime')
-rw-r--r--src/libmime/mime_headers.c74
-rw-r--r--src/libmime/mime_headers.h8
2 files changed, 81 insertions, 1 deletions
diff --git a/src/libmime/mime_headers.c b/src/libmime/mime_headers.c
index 2b6b2acc0..e250e84f1 100644
--- a/src/libmime/mime_headers.c
+++ b/src/libmime/mime_headers.c
@@ -1025,6 +1025,76 @@ rspamd_message_headers_new(void)
return nhdrs;
}
+gsize rspamd_message_header_unfold_inplace(char *hdr, gsize len)
+{
+ /*
+ * t - tortoise (destination)
+ * h - hare (source)
+ */
+ char *t = hdr, *h = hdr, *end = (hdr + len);
+ enum {
+ copy_chars,
+ folding_cr,
+ folding_lf,
+ folding_ws,
+ } state = copy_chars;
+
+ while (h < end) {
+ switch (state) {
+ case copy_chars:
+ if (*h == '\r') {
+ state = folding_cr;
+ h++;
+ }
+ else if (*h == '\n') {
+ state = folding_lf;
+ h++;
+ }
+ else {
+ *t++ = *h++;
+ }
+ break;
+ case folding_cr:
+ if (*h == '\n') {
+ state = folding_lf;
+ h++;
+ }
+ else if (g_ascii_isspace(*h)) {
+ state = folding_ws;
+ h++;
+ }
+ else {
+ /* It is weird, not like a folding, so we need to revert back */
+ *t++ = '\r';
+ state = copy_chars;
+ }
+ break;
+ case folding_lf:
+ if (g_ascii_isspace(*h)) {
+ state = folding_ws;
+ h++;
+ }
+ else {
+ /* It is weird, not like a folding, so we need to revert back */
+ *t++ = '\n';
+ state = copy_chars;
+ }
+ break;
+ case folding_ws:
+ if (!g_ascii_isspace(*h)) {
+ *t++ = ' ';
+ state = copy_chars;
+ }
+ else {
+ h++;
+ }
+ break;
+ }
+ }
+
+ return t - hdr;
+}
+
void rspamd_message_set_modified_header(struct rspamd_task *task,
struct rspamd_mime_headers_table *hdrs,
const gchar *hdr_name,
@@ -1201,8 +1271,10 @@ void rspamd_message_set_modified_header(struct rspamd_task *task,
nhdr->name = hdr_elt->name;
nhdr->value = rspamd_mempool_alloc(task->task_pool,
raw_len + 1);
+ /* Strlcpy will ensure that value will have no embedded \0 */
rspamd_strlcpy(nhdr->value, raw_value, raw_len + 1);
- /* TODO: unfold header value, sigh */
+ gsize value_len = rspamd_message_header_unfold_inplace(nhdr->value, raw_len);
+ nhdr->value[value_len] = '\0';
/* Deal with the raw value */
size_t namelen = strlen(hdr_elt->name);
diff --git a/src/libmime/mime_headers.h b/src/libmime/mime_headers.h
index ffa863e8b..60015a20e 100644
--- a/src/libmime/mime_headers.h
+++ b/src/libmime/mime_headers.h
@@ -185,6 +185,14 @@ bool rspamd_mime_headers_foreach(const struct rspamd_mime_headers_table *,
*/
gsize rspamd_strip_smtp_comments_inplace(gchar *input, gsize len);
+/**
+ * Unfold header in place
+ * @param hdr header value
+ * @param len length of the header
+ * @return new unfolded length
+ */
+gsize rspamd_message_header_unfold_inplace(char *hdr, gsize len);
+
#ifdef __cplusplus
}
#endif