pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/43750?usp=email )
Change subject: Misc_Helpers: Fix f_str_(oct_)split() skipping empty strings ......................................................................
Misc_Helpers: Fix f_str_(oct_)split() skipping empty strings
Default behavior should be to return proper splitting including empty chunks too, otherwise it's impossible under some scenarios to discern between input string where number of delimiters matter.
A new skip_empty_chunks param is added (disabled by default) to allow skipping empty strings, since this is helpful under some situations and more efficient than splitting then re-creating the returned list removing empty strings (or skipping them in a loop).
Change-Id: I69a20b4659e3c701bd3c9f7c72ea8127feddb006 --- M library/HTTP2_Functions.ttcn M library/Misc_Helpers.ttcn M library/Osmocom_VTY_Functions.ttcn M library/Prometheus_Checker.ttcn 4 files changed, 22 insertions(+), 13 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/50/43750/1
diff --git a/library/HTTP2_Functions.ttcn b/library/HTTP2_Functions.ttcn index 307938b..14f03ce 100644 --- a/library/HTTP2_Functions.ttcn +++ b/library/HTTP2_Functions.ttcn @@ -55,12 +55,9 @@ var HTTP2_header_list li := {}; var charstring data_str := oct2char(data); var charstring delim := "\r\n"; - var ro_charstring sp := f_str_split(data_str, delim); + var ro_charstring sp := f_str_split(data_str, delim, skip_empty_chunks := true); var charstring line_regexp := "([A-Za-z][A-Za-z0-9-]+):\s#()(?+)\s#()"; for (var integer i := 0; i < lengthof(sp); i := i + 1) { - if (sp[i] == "") { - continue; - } var charstring header_name := regexp(sp[i], line_regexp, 0); var charstring header_value := regexp(sp[i], line_regexp, 1); li := li & { valueof(ts_HTTP2_header_field(header_name, header_value)) }; @@ -77,6 +74,11 @@ /* 0..off is headers, off+lengthof(delim)..end is the data. * Furthermore, data contains an extra "\r\n" at the end. */ var integer off := f_strstr_oct(data, delim, 0); + if (off < 0) { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("f_strstr_oct(data=",data, ", delim=", delim, ", 0) returned negative")); + + } var octetstring header := substr(data, 0, off); off := off + lengthof(delim);
@@ -110,8 +112,8 @@ log2str("Unexpected parsing multipart ", data, " into ", parts)); }
- /* Parse each part and put it in the list: */ - for (var integer i := 0; i < lengthof(parts) - 1; i := i + 1) { + /* Parse each part and put it in the list: Start after 1st boundary, and avoid after last one (see check above) */ + for (var integer i := 1; i < lengthof(parts) - 1; i := i + 1) { li := li & { f_HTTP2_multipart_msg_parse_part(parts[i]) }; } return li; diff --git a/library/Misc_Helpers.ttcn b/library/Misc_Helpers.ttcn index 24d0590..eb63a2c 100644 --- a/library/Misc_Helpers.ttcn +++ b/library/Misc_Helpers.ttcn @@ -114,8 +114,11 @@ return new_str; }
+/* Return a list of the substrings in string "str", using "delim" as the delimiter string. + * If skip_empty_chunks is true, empty substrings resulting from 2 consecutive "delim" tokens + * are NOT added to the returned list. This is useful for instance to skip empty lines while splitting. */ type record of charstring ro_charstring; -function f_str_split(charstring str, charstring delim := "\n") return ro_charstring +function f_str_split(charstring str, charstring delim := "\n", boolean skip_empty_chunks := false) return ro_charstring { var integer pos := 0; var ro_charstring parts := {}; @@ -128,6 +131,8 @@ } if (delim_pos > pos) { parts := parts & { substr(str, pos, delim_pos - pos) }; + } else if (not skip_empty_chunks and (delim_pos == pos)) { + parts := parts & { "" }; } pos := delim_pos + lengthof(delim); } @@ -136,7 +141,7 @@
/* Same as f_str_split() but using octetstring */ type record of octetstring ro_octetstring; -function f_str_oct_split(octetstring str, octetstring delim := ''O) return ro_octetstring +function f_str_oct_split(octetstring str, octetstring delim := ''O, boolean skip_empty_chunks := false) return ro_octetstring { var integer pos := 0; var ro_octetstring parts := {}; @@ -149,6 +154,8 @@ } if (delim_pos > pos) { parts := parts & { substr(str, pos, delim_pos - pos) }; + } else if (not skip_empty_chunks and (delim_pos == pos)) { + parts := parts & { ''O }; } pos := delim_pos + lengthof(delim); } diff --git a/library/Osmocom_VTY_Functions.ttcn b/library/Osmocom_VTY_Functions.ttcn index 7dd5c59..f99a13b 100644 --- a/library/Osmocom_VTY_Functions.ttcn +++ b/library/Osmocom_VTY_Functions.ttcn @@ -288,7 +288,7 @@ attempts := attempts - 1; var charstring ret := f_vty_transceive_ret(pt, show_cmd);
- var Misc_Helpers.ro_charstring lines := f_str_split(ret); + var Misc_Helpers.ro_charstring lines := f_str_split(ret, skip_empty_chunks := true);
var boolean ok := true; for (var integer i := 0; i < lengthof(object_strs); i := i + 1) { @@ -301,7 +301,7 @@ if (f_strstr(line, object_str) < 0) { continue; } - var Misc_Helpers.ro_charstring tokens := f_str_split(line, " "); + var Misc_Helpers.ro_charstring tokens := f_str_split(line, " ", skip_empty_chunks := true); if (lengthof(tokens) < 4) { continue; } diff --git a/library/Prometheus_Checker.ttcn b/library/Prometheus_Checker.ttcn index 061b0fd..870a728 100644 --- a/library/Prometheus_Checker.ttcn +++ b/library/Prometheus_Checker.ttcn @@ -115,7 +115,7 @@ private function f_prometheus_parse_http_response(charstring body) return PrometheusMetrics { var PrometheusMetrics metrics := {}; - var Misc_Helpers.ro_charstring lines := f_str_split(body, "\n"); + var Misc_Helpers.ro_charstring lines := f_str_split(body, "\n", skip_empty_chunks := true); for (var integer i := 0; i + 2 < lengthof(lines); i := i + 3) { var PrometheusMetric it; /* HELP line, example: "# HELP cx_rx_unknown Received Cx unknown messages" */ @@ -129,7 +129,7 @@ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Failed parsing Prometheus HTTP response line: ", lines[i + 1])); } - var Misc_Helpers.ro_charstring type_tokens := f_str_split(lines[i + 1], " "); + var Misc_Helpers.ro_charstring type_tokens := f_str_split(lines[i + 1], " ", skip_empty_chunks := true); if (lengthof(type_tokens) < 4) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Failed parsing Prometheus HTTP response line: ", type_tokens)); @@ -142,7 +142,7 @@ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Failed parsing Prometheus HTTP response line: ", lines[i + 2])); } - var Misc_Helpers.ro_charstring value_tokens := f_str_split(lines[i + 2], " "); + var Misc_Helpers.ro_charstring value_tokens := f_str_split(lines[i + 2], " ", skip_empty_chunks := true); it.val := str2int(value_tokens[1]);
metrics := metrics & { it };