You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mk...@apache.org on 2019/01/27 18:45:56 UTC

[lucene-solr] branch master updated: LUCENE-8640: date range syntax validation

This is an automated email from the ASF dual-hosted git repository.

mkhl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/master by this push:
     new 8e69d12  LUCENE-8640: date range syntax validation
8e69d12 is described below

commit 8e69d12dd7e2b6d2341322e4ac7e5c33b789507a
Author: Mikhail Khludnev <mk...@apache.org>
AuthorDate: Sat Jan 26 23:25:41 2019 +0300

    LUCENE-8640: date range syntax validation
---
 lucene/CHANGES.txt                                 |  2 +
 .../spatial/prefix/tree/DateRangePrefixTree.java   | 46 ++++++++++++++++++----
 .../prefix/tree/DateRangePrefixTreeTest.java       | 43 ++++++++++++++++++++
 3 files changed, 84 insertions(+), 7 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 04f4960..fd35d8e 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -324,6 +324,8 @@ Improvements
 * LUCENE-8527: Upgrade JFlex dependency to 1.7.0; in StandardTokenizer and UAX29URLEmailTokenizer,
   increase supported Unicode version from 6.3 to 9.0, and support Unicode UTS#51 v11.0 Emoji tokenization.
 
+* LUCENE-8640: Date Range format validation (Lucky Sharma, David Smiley via Mikhail Khludnev)
+
 Optimizations
 
 * LUCENE-8552: FieldInfos.getMergedFieldInfos no longer does any merging if there is <= 1 segment.
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/tree/DateRangePrefixTree.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/tree/DateRangePrefixTree.java
index cc47358..31e0a00 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/tree/DateRangePrefixTree.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/tree/DateRangePrefixTree.java
@@ -446,6 +446,7 @@ public class DateRangePrefixTree extends NumberRangePrefixTree {
     if (str.equals("*"))
       return cal;
     int offset = 0;//a pointer
+    int parsedVal = 0;
     try {
       //year & era:
       int lastOffset = str.charAt(str.length()-1) == 'Z' ? str.length() - 1 : str.length();
@@ -463,41 +464,72 @@ public class DateRangePrefixTree extends NumberRangePrefixTree {
       // The str.substring()'s hopefully get optimized to be stack-allocated.
 
       //month:
-      cal.set(Calendar.MONTH, Integer.parseInt(str.substring(offset, offset+2)) - 1);//starts at 0
+      parsedVal = parseAndCheck( str, offset, 1, 12);
+      cal.set(Calendar.MONTH, parsedVal - 1);//starts at 0
       offset += 3;
       if (lastOffset < offset)
         return cal;
       //day:
-      cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(str.substring(offset, offset+2)));
+      checkDelimeter(str, offset-1, '-');
+
+      parsedVal = parseAndCheck( str, offset, 1, 31);
+      cal.set(Calendar.DAY_OF_MONTH, parsedVal);
       offset += 3;
       if (lastOffset < offset)
         return cal;
+      checkDelimeter(str, offset-1, 'T');
       //hour:
-      cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(str.substring(offset, offset+2)));
+
+      parsedVal = parseAndCheck( str, offset, 0, 24);
+      cal.set(Calendar.HOUR_OF_DAY, parsedVal);
       offset += 3;
       if (lastOffset < offset)
         return cal;
+      checkDelimeter(str, offset-1, ':');
       //minute:
-      cal.set(Calendar.MINUTE, Integer.parseInt(str.substring(offset, offset+2)));
+
+      parsedVal = parseAndCheck( str, offset, 1, 60);
+      cal.set(Calendar.MINUTE, parsedVal);
       offset += 3;
       if (lastOffset < offset)
         return cal;
+      checkDelimeter(str, offset-1, ':');
       //second:
-      cal.set(Calendar.SECOND, Integer.parseInt(str.substring(offset, offset+2)));
+
+      parsedVal = parseAndCheck( str, offset, 1, 60);
+      cal.set(Calendar.SECOND, parsedVal);
       offset += 3;
       if (lastOffset < offset)
         return cal;
+      checkDelimeter(str, offset-1, '.');
       //ms:
+
       cal.set(Calendar.MILLISECOND, Integer.parseInt(str.substring(offset, offset+3)));
       offset += 3;//last one, move to next char
       if (lastOffset == offset)
         return cal;
     } catch (Exception e) {
-      ParseException pe = new ParseException("Improperly formatted date: "+str, offset);
+      ParseException pe = new ParseException("Improperly formatted datetime: "+str, offset);
       pe.initCause(e);
       throw pe;
     }
-    throw new ParseException("Improperly formatted date: "+str, offset);
+    throw new ParseException("Improperly formatted datetime: "+str, offset);
+  }
+
+  private  void checkDelimeter(String str, int offset, char delim) {
+    if (str.charAt(offset) != delim) {
+      throw new IllegalArgumentException("Invalid delimeter: '"+str.charAt(offset)+
+          "', expecting '"+delim+"'");
+    }
+  }
+
+  private int parseAndCheck(String  str, int offset, int min, int max) {
+    int val = Integer.parseInt(str.substring(offset, offset+2));
+    if (val < min  || val > max) {
+      throw new IllegalArgumentException("Invalid value: "+val+"," +
+          " expecting from "+min+" to "+max+"]");
+    }
+    return val;
   }
 
 }
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/tree/DateRangePrefixTreeTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/tree/DateRangePrefixTreeTest.java
index d29a192..f9f3d12 100644
--- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/tree/DateRangePrefixTreeTest.java
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/tree/DateRangePrefixTreeTest.java
@@ -210,4 +210,47 @@ public class DateRangePrefixTreeTest extends LuceneTestCase {
     assertEquals("[* TO 2014-09-15]", tree.parseShape("[* TO 2014-09-15]").toString());
   }
 
+  public void testInvalidDateException() throws ParseException {
+    
+    expectThrows(ParseException.class, () -> {
+      tree.parseCalendar("2000-11T13");
+    });
+    expectThrows(ParseException.class, () -> {
+      tree.parseCalendar("2000-11-10T13-1");
+    });
+    {
+        String causeMessage = expectThrows(ParseException.class, () -> {
+          tree.parseCalendar("2000-11-10T13Z1");
+        }).getCause().getMessage();
+        assertTrue(causeMessage +" has actual delimeter", causeMessage.contains("Z"));
+        assertTrue(causeMessage +" has expected delimeter",causeMessage.contains(":"));
+        assertFalse(causeMessage +" has no input",causeMessage.contains("2000-11-10"));
+    }
+    expectThrows(ParseException.class, () -> {
+      tree.parseCalendar("2000T13Z");
+    });
+    expectThrows(ParseException.class, () -> {
+      tree.parseCalendar("2000-11T13Z");
+    });
+    {
+      String causeMessage = expectThrows(ParseException.class, () -> {
+        tree.parseCalendar("2000-13-12");
+      }).getCause().getMessage();
+      assertTrue(causeMessage +" has actual value",causeMessage.contains("13"));
+      assertFalse(causeMessage +" has no input",causeMessage.contains("2000-13-12"));
+    }
+    expectThrows(ParseException.class, () -> {
+      tree.parseCalendar("2000-13-41T13Z");
+    });
+    expectThrows(ParseException.class, () -> {
+      tree.parseCalendar("2000-11-12T25Z");
+    });
+    expectThrows(ParseException.class, () -> {
+      tree.parseCalendar("2000-11-12T25:61Z");
+    });
+    expectThrows(ParseException.class, () -> {
+      tree.parseCalendar("2000-11-12T25:14:61Z");
+    });
+  }
+
 }
\ No newline at end of file