Browse Source

pv_headers: fix detection of split marker

If we set Diversion in split_headers and we get a header like
> "RULTEST, normalaa" <sip:[email protected];user=phone>;reason=unconditional

There was false detection of two Diversion headers.

Skip split marker between double quotes to avoid this
Victor Seva 4 years ago
parent
commit
c05c7133a5

+ 3 - 2
src/modules/pv_headers/pvh_func.c

@@ -62,6 +62,7 @@ int pvh_collect_headers(struct sip_msg *msg)
 	char hvals[header_name_size][header_value_size];
 	int idx = 0, d_size = 0;
 	str val_part = STR_NULL;
+	char *marker = NULL;
 
 	if(pvh_hdrs_collected(msg)) {
 		LM_ERR("headers are already collected\n");
@@ -95,10 +96,10 @@ int pvh_collect_headers(struct sip_msg *msg)
 		val.len = hf->body.len;
 		val.s = hf->body.s;
 
-		if(strchr(val.s, ',') != NULL
+		if(( marker = pvh_detect_split_char(val.s)) != NULL
 				&& str_hash_case_get(&split_headers, name.s, name.len)) {
 
-			if(pvh_split_values(&val, hvals, &d_size, 1) < 0) {
+			if(pvh_split_values(&val, hvals, &d_size, 1, marker) < 0) {
 				LM_ERR("could not parse %.*s header comma separated "
 					   "value",
 						name.len, name.s);

+ 1 - 1
src/modules/pv_headers/pvh_hash.c

@@ -37,7 +37,7 @@ int pvh_str_hash_init(struct str_hash_table *ht, str *keys, char *desc)
 	int idx = 0, d_size = 0;
 	str val = STR_NULL;
 
-	if(pvh_split_values(keys, split, &d_size, 0) < 0) {
+	if(pvh_split_values(keys, split, &d_size, 0, NULL) < 0) {
 		LM_ERR("could not parse %s param\n", desc);
 		return -1;
 	}

+ 42 - 8
src/modules/pv_headers/pvh_str.c

@@ -103,10 +103,39 @@ int pvh_extract_display_uri(char *suri, str *display, str *duri)
 	return 1;
 }
 
-int pvh_split_values(
-		str *s, char d[][header_value_size], int *d_size, int keep_spaces)
+char *pvh_detect_split_char(char *val)
 {
-	char p;
+	char *quote_a = NULL, *quote_b = NULL;
+	char *split = NULL;
+
+	if(val == NULL)
+		return NULL;
+
+	split = strchr(val, ',');
+	if(split == NULL) {
+		LM_DBG("no split marker detected\n");
+		return NULL;
+	}
+
+	quote_a = strchr(val, '"');
+	if(quote_a == NULL || split < quote_a) {
+		LM_DBG("split marker detected[%ld], not between quotes\n", split - val);
+		return split;
+	}
+
+	quote_b = strchr(val + (split - quote_a + 1), '"');
+	if(quote_b == NULL) {
+		LM_DBG("split marker detected[%ld], quote occurrence unbalanced[%ld]\n",
+				split - val, quote_b - val);
+		return split;
+	}
+	return pvh_detect_split_char(val + (quote_b - val + 1));
+}
+
+int pvh_split_values(str *s, char d[][header_value_size], int *d_size,
+		int keep_spaces, char *marker)
+{
+	char *p = NULL;
 	int idx = 0, c_idx = 0;
 
 	*d_size = -1;
@@ -115,12 +144,17 @@ int pvh_split_values(
 		*d_size = 0;
 		return 1;
 	}
-
+	if(!marker)
+		marker = pvh_detect_split_char(s->s);
 	while(idx < s->len) {
-		strncpy(&p, s->s + idx++, 1);
-		if(keep_spaces == 0 && strncmp(&p, " ", 1) == 0)
+		p = s->s + idx++;
+		if(keep_spaces == 0 && strncmp(p, " ", 1) == 0)
 			continue;
-		if(strncmp(&p, ",", 1) == 0) {
+		if(p == marker) {
+			if(marker && idx < s->len) {
+				LM_DBG("search next split marker[%d]\n", idx);
+				marker = pvh_detect_split_char(p + 1);
+			}
 			if(c_idx == 0)
 				continue;
 			if(c_idx + 1 < header_value_size)
@@ -131,7 +165,7 @@ int pvh_split_values(
 		}
 		if(c_idx == 0)
 			(*d_size)++;
-		strncpy(&d[*d_size][c_idx++], &p, 1);
+		strncpy(&d[*d_size][c_idx++], p, 1);
 	}
 
 	if(c_idx > 0) {

+ 3 - 2
src/modules/pv_headers/pvh_str.h

@@ -34,7 +34,8 @@ int pvh_str_new(str *s, int size);
 int pvh_str_free(str *s);
 int pvh_str_copy(str *dst, str *src, unsigned int max_size);
 int pvh_extract_display_uri(char *suri, str *display, str *duri);
-int pvh_split_values(
-		str *s, char d[][header_value_size], int *d_size, int keep_spaces);
+char *pvh_detect_split_char(char *s);
+int pvh_split_values(str *s, char d[][header_value_size], int *d_size,
+		int keep_spaces, char *marker);
 
 #endif /* PV_STR_H */