Added more invalid binding keys to Gremlin Server OpProcessor validation.

These "invalid" keys are reserved terms for Gremlin Server as they are 
statically imported enums and shouldn't be used as binding keys. You get some 
less than easy to understand error messages if those keys are used.


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/c37c3016
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/c37c3016
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/c37c3016

Branch: refs/heads/TINKERPOP-1254
Commit: c37c3016bd05b3caeb09084f5469c606c439bfe5
Parents: 1c9bd08
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Jun 30 13:07:44 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Jun 30 13:07:44 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../upgrade/release-3.1.x-incubating.asciidoc   | 12 +++++
 .../gremlin/process/traversal/Scope.java        |  2 -
 .../server/op/AbstractEvalOpProcessor.java      | 54 +++++++++++++++++---
 .../server/GremlinServerIntegrateTest.java      | 21 +++++++-
 5 files changed, 79 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c37c3016/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 2ae2e77..3fd646a 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -33,6 +33,7 @@ TinkerPop 3.1.3 (NOT OFFICIALLY RELEASED YET)
 * Improved `TinkerGraph` performance when iterating vertices and edges.
 * Fixed a bug where timeout functions provided to the `GremlinExecutor` were 
not executing in the same thread as the script evaluation.
 * Optimized a few special cases in `RangeByIsCountStrategy`.
+* Added more "invalid" variable bindings to the list used by Gremlin Server to 
validate incoming bindings on requests.
 * Named the thread pool used by Gremlin Server sessions: 
"gremlin-server-session-$n".
 * Fixed a bug in `BulkSet.equals()` which made itself apparent when using 
`store()` and `aggregate()` with labeled `cap()`.
 * Fixed a bug where `Result.one()` could potentially block indefinitely under 
certain circumstances.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c37c3016/docs/src/upgrade/release-3.1.x-incubating.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade/release-3.1.x-incubating.asciidoc 
b/docs/src/upgrade/release-3.1.x-incubating.asciidoc
index b1b99f8..504baaa 100644
--- a/docs/src/upgrade/release-3.1.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.1.x-incubating.asciidoc
@@ -32,6 +32,16 @@ Please see the 
link:https://github.com/apache/incubator-tinkerpop/blob/3.1.3/CHA
 Upgrading for Users
 ~~~~~~~~~~~~~~~~~~~
 
+Reserved Gremlin Server Keys
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Gremlin Server has always considered certain binding keys (request parameters) 
as reserved, but that list has now
+expanded to be more inclusive all the static enums that are imported to the 
script engine. It is possible that those
+using Gremlin Server may have to rename their keys if they somehow 
successfully were using some of the now reserved
+terms in previous versions.
+
+See: https://issues.apache.org/jira/browse/TINKERPOP-1354[TINKERPOP-1354]
+
 Remote Timeout
 ^^^^^^^^^^^^^^
 
@@ -54,6 +64,8 @@ set to `none`.
 
 See: https://issues.apache.org/jira/browse/TINKERPOP-1267[TINKERPOP-1267]
 
+
+
 Upgrading for Providers
 ~~~~~~~~~~~~~~~~~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c37c3016/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Scope.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Scope.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Scope.java
index 1cce1e0..11979de 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Scope.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Scope.java
@@ -18,8 +18,6 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal;
 
-import java.util.Map;
-
 /**
  * Many {@link Step} instance can have a variable scope.
  * {@link Scope#global}: the step operates on the entire traversal.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c37c3016/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
----------------------------------------------------------------------
diff --git 
a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
 
b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
index a5dd0a0..f712b44 100644
--- 
a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
+++ 
b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
@@ -28,10 +28,15 @@ import 
org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.driver.ser.MessageTextSerializer;
 import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
 import 
org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.TimedInterruptTimeoutException;
+import org.apache.tinkerpop.gremlin.process.traversal.Operator;
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.server.GraphManager;
 import org.apache.tinkerpop.gremlin.server.handler.Frame;
 import org.apache.tinkerpop.gremlin.server.handler.GremlinResponseFrameEncoder;
 import org.apache.tinkerpop.gremlin.server.handler.StateKey;
+import org.apache.tinkerpop.gremlin.structure.Column;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.server.Context;
 import org.apache.tinkerpop.gremlin.server.GremlinServer;
@@ -54,11 +59,13 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.function.Supplier;
 import java.util.regex.Pattern;
+import java.util.stream.Stream;
 
 import static com.codahale.metrics.MetricRegistry.name;
 
@@ -84,7 +91,12 @@ public abstract class AbstractEvalOpProcessor implements 
OpProcessor {
 
     /**
      * Regex for validating that binding variables.
+     *
+     * @deprecated As of release 3.1.2-incubating, not replaced. This {@code 
Pattern} is not used internally.
+     * Deprecated rather than just removing as it's possible that someone else 
might be using it when developing
+     * custom {@link OpProcessor} implementations.
      */
+    @Deprecated
     protected static final Pattern validBindingName = 
Pattern.compile("[a-zA-Z$_][a-zA-Z0-9$_]*");
 
     /**
@@ -95,12 +107,37 @@ public abstract class AbstractEvalOpProcessor implements 
OpProcessor {
      * Use of {@code toUpperCase()} on the accessor values of {@link T} solves 
an issue where the {@code ScriptEngine}
      * ignores private scope on {@link T} and imports static fields.
      */
-    private static final List<String> invalidBindingsKeys = Arrays.asList(
-            T.id.getAccessor(), T.key.getAccessor(),
-            T.label.getAccessor(), T.value.getAccessor(),
-            T.id.getAccessor().toUpperCase(), 
T.key.getAccessor().toUpperCase(),
-            T.label.getAccessor().toUpperCase(), 
T.value.getAccessor().toUpperCase());
-    private static final String invalidBindingKeysJoined = String.join(",", 
invalidBindingsKeys);
+    protected static final Set<String> INVALID_BINDINGS_KEYS = new HashSet<>();
+
+    static {
+        INVALID_BINDINGS_KEYS.addAll(Arrays.asList(
+                T.id.name(), T.key.name(),
+                T.label.name(), T.value.name(),
+                T.id.getAccessor(), T.key.getAccessor(),
+                T.label.getAccessor(), T.value.getAccessor(),
+                T.id.getAccessor().toUpperCase(), 
T.key.getAccessor().toUpperCase(),
+                T.label.getAccessor().toUpperCase(), 
T.value.getAccessor().toUpperCase()));
+
+        for (Column enumItem : Column.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+
+        for (Order enumItem : Order.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+
+        for (Operator enumItem : Operator.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+
+        for (Scope enumItem : Scope.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+
+        for (Pop enumItem : Pop.values()) {
+            INVALID_BINDINGS_KEYS.add(enumItem.name());
+        }
+    }
 
     protected final boolean manageTransactions;
 
@@ -155,8 +192,9 @@ public abstract class AbstractEvalOpProcessor implements 
OpProcessor {
                 throw new OpProcessorException(msg, 
ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
             }
 
-            if 
(bindings.keySet().stream().anyMatch(invalidBindingsKeys::contains)) {
-                final String msg = String.format("The [%s] message is using at 
least one of the invalid binding key of [%s]. It conflicts with standard static 
imports to Gremlin Server.", Tokens.OPS_EVAL, invalidBindingKeysJoined);
+            final Set<String> badBindings = 
IteratorUtils.set(IteratorUtils.<String>filter(bindings.keySet().iterator(), 
INVALID_BINDINGS_KEYS::contains));
+            if (!badBindings.isEmpty()) {
+                final String msg = String.format("The [%s] message supplies 
one or more invalid parameters key of [%s] - these are reserved names.", 
Tokens.OPS_EVAL, badBindings);
                 throw new OpProcessorException(msg, 
ResponseMessage.build(message).code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(msg).create());
             }
         }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c37c3016/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
----------------------------------------------------------------------
diff --git 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
index 99bb745..2f091d9 100644
--- 
a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
+++ 
b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
@@ -55,7 +55,6 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.nio.channels.ClosedChannelException;
-import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -412,6 +411,26 @@ public class GremlinServerIntegrateTest extends 
AbstractGremlinServerIntegration
                 fail("Request should have returned error, but instead timed 
out");
             assertTrue(pass.get());
         }
+
+        try (SimpleClient client = new WebSocketClient()) {
+            final Map<String, Object> bindings = new HashMap<>();
+            bindings.put("id", "123");
+            final RequestMessage request = 
RequestMessage.build(Tokens.OPS_EVAL)
+                    .addArg(Tokens.ARGS_GREMLIN, "[1,2,3,4,5,6,7,8,9,0]")
+                    .addArg(Tokens.ARGS_BINDINGS, bindings).create();
+            final CountDownLatch latch = new CountDownLatch(1);
+            final AtomicBoolean pass = new AtomicBoolean(false);
+            client.submit(request, result -> {
+                if (result.getStatus().getCode() != 
ResponseStatusCode.PARTIAL_CONTENT) {
+                    
pass.set(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS == 
result.getStatus().getCode());
+                    latch.countDown();
+                }
+            });
+
+            if (!latch.await(3000, TimeUnit.MILLISECONDS))
+                fail("Request should have returned error, but instead timed 
out");
+            assertTrue(pass.get());
+        }
     }
 
     @Test

Reply via email to