diff --git a/prometheus_client/openmetrics/parser.py b/prometheus_client/openmetrics/parser.py index 3e285093..50fa3419 100644 --- a/prometheus_client/openmetrics/parser.py +++ b/prometheus_client/openmetrics/parser.py @@ -139,9 +139,12 @@ def _parse_labels_with_state_machine(text): if char == '\\': state = 'labelvalueslash' elif char == '"': - if not METRIC_LABEL_NAME_RE.match(''.join(labelname)): - raise ValueError("Invalid line: " + text) - labels[''.join(labelname)] = ''.join(labelvalue) + ln = ''.join(labelname) + if not METRIC_LABEL_NAME_RE.match(ln): + raise ValueError("Invalid line, bad label name: " + text) + if ln in labels: + raise ValueError("Invalid line, duplicate label name: " + text) + labels[ln] = ''.join(labelvalue) labelname = [] labelvalue = [] state = 'endoflabelvalue' @@ -217,6 +220,10 @@ def _parse_labels(text): # Replace escaping if needed if "\\" in label_value: label_value = _replace_escaping(label_value) + if not METRIC_LABEL_NAME_RE.match(label_name): + raise ValueError("invalid line, bad label name: " + text) + if label_name in labels: + raise ValueError("invalid line, duplicate label name: " + text) labels[label_name] = label_value # Remove the processed label from the sub-slice for next iteration diff --git a/tests/openmetrics/test_parser.py b/tests/openmetrics/test_parser.py index 81873388..63dd5e42 100644 --- a/tests/openmetrics/test_parser.py +++ b/tests/openmetrics/test_parser.py @@ -560,6 +560,11 @@ def test_invalid_input(self): ('a{a="1"b="2"} 1\n# EOF\n'), ('a{a="1",,b="2"} 1\n# EOF\n'), ('a{a="1",b="2",} 1\n# EOF\n'), + # Invalid labels. + ('a{1="1"} 1\n# EOF\n'), + ('a{a="1",a="1"} 1\n# EOF\n'), + ('a{1=" # "} 1\n# EOF\n'), + ('a{a=" # ",a=" # "} 1\n# EOF\n'), # Missing value. ('a\n# EOF\n'), ('a \n# EOF\n'),