]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 877545: quicksearch shouldn't treat apostrophes as quote characters
authorByron Jones <bjones@mozilla.com>
Wed, 18 Sep 2013 07:59:09 +0000 (15:59 +0800)
committerByron Jones <bjones@mozilla.com>
Wed, 18 Sep 2013 07:59:09 +0000 (15:59 +0800)
r=simon, a=glob

Bugzilla/Search/Quicksearch.pm

index 3048de2376aeb36be387bec241777f77b79c0328..c7dfaeb8f0837916c0a74e337fbc68929223d1cc 100644 (file)
@@ -138,7 +138,7 @@ sub quicksearch {
 
         # Retain backslashes and quotes, to know which strings are quoted,
         # and which ones are not.
-        my @words = parse_line('\s+', 1, $searchstring);
+        my @words = _parse_line('\s+', 1, $searchstring);
         # If parse_line() returns no data, this means strings are badly quoted.
         # Rather than trying to guess what the user wanted to do, we throw an error.
         scalar(@words)
@@ -194,7 +194,7 @@ sub quicksearch {
 
         # Loop over all main-level QuickSearch words.
         foreach my $qsword (@qswords) {
-            my @or_operand = parse_line('\|', 1, $qsword);
+            my @or_operand = _parse_line('\|', 1, $qsword);
             foreach my $term (@or_operand) {
                 my $negate = substr($term, 0, 1) eq '-';
                 if ($negate) {
@@ -208,7 +208,7 @@ sub quicksearch {
                 # Having ruled out the special cases, we may now split
                 # by comma, which is another legal boolean OR indicator.
                 # Remove quotes from quoted words, if any.
-                @words = parse_line(',', 0, $term);
+                @words = _parse_line(',', 0, $term);
                 foreach my $word (@words) {
                     if (!_special_field_syntax($word, $negate)) {
                         _default_quicksearch_word($word, $negate);
@@ -260,6 +260,27 @@ sub quicksearch {
 # Parts of quicksearch() #
 ##########################
 
+sub _parse_line {
+    my ($delim, $keep, $line) = @_;
+    # parse_line always treats ' as a quote character, making it impossible
+    # to sanely search for contradictions. As this behavour isn't
+    # configurable, we replace ' with a placeholder to hide it from the
+    # parser.
+
+    # only treat ' at the start or end of words as quotes
+    # it's easier to do this in reverse with regexes
+    $line =~ s/(^|\s|:)'/$1\001/g;
+    $line =~ s/'($|\s)/\001$1/g;
+    $line =~ s/\\?'/\000/g;
+    $line =~ tr/\001/'/;
+
+    my @words = parse_line($delim, $keep, $line);
+    foreach my $word (@words) {
+        $word =~ tr/\000/'/;
+    }
+    return @words;
+}
+
 sub _bug_numbers_only {
     my $searchstring = shift;
     my $cgi = Bugzilla->cgi;
@@ -365,10 +386,10 @@ sub _handle_field_names {
 
     # Generic field1,field2,field3:value1,value2 notation.
     # We have to correctly ignore commas and colons in quotes.
-    my @field_values = parse_line(':', 1, $or_operand);
+    my @field_values = _parse_line(':', 1, $or_operand);
     if (scalar @field_values == 2) {
-        my @fields = parse_line(',', 1, $field_values[0]);
-        my @values = parse_line(',', 1, $field_values[1]);
+        my @fields = _parse_line(',', 1, $field_values[0]);
+        my @values = _parse_line(',', 1, $field_values[1]);
         foreach my $field (@fields) {
             my $translated = _translate_field_name($field);
             # Skip and record any unknown fields