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

frankgh pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 99320f22 CASSSIDECAR-361: Fast Cassandra Input Validator (#273)
99320f22 is described below

commit 99320f22ae58b6e81c8db5442138d95e0182c38c
Author: Francisco Guerrero <[email protected]>
AuthorDate: Sat Nov 8 15:06:38 2025 -0800

    CASSSIDECAR-361: Fast Cassandra Input Validator (#273)
    
    Patch by Francisco Guerrero; reviewed by Saranya Krishnakumar for 
CASSSIDECAR-361
---
 CHANGES.txt                                        |   1 +
 conf/sidecar.yaml                                  |  21 +-
 docs/src/user.adoc                                 |  11 +-
 examples/conf/sidecar-ccm.yaml                     |   4 +-
 .../CassandraInputValidationConfiguration.java     |   5 +
 .../CassandraInputValidationConfigurationImpl.java |  30 +-
 .../exceptions/CassandraInputException.java        |  30 ++
 .../ForbiddenCassandraInputException.java          |  30 ++
 .../sidecar/handlers/AbstractHandler.java          |   6 +
 .../cassandra/sidecar/modules/UtilitiesModule.java |  27 ++
 .../sidecar/snapshots/SnapshotPathBuilder.java     |  14 +-
 .../sidecar/utils/CassandraInputValidator.java     | 172 ++---------
 .../sidecar/utils/FastCassandraInputValidator.java | 314 +++++++++++++++++++++
 ...java => RegexBasedCassandraInputValidator.java} | 170 +++++------
 .../sidecar/config/SidecarConfigurationTest.java   |  17 +-
 .../sidecar/utils/CassandraInputValidatorTest.java | 154 ++++++----
 .../utils/FastCassandraInputValidatorTest.java     | 105 +++++++
 .../RegexBasedCassandraInputValidatorTest.java     |  75 +++++
 .../resources/config/sidecar_file_permissions.yaml |   4 +-
 .../sidecar_invalid_accesscontrol_config.yaml      |   4 +-
 .../config/sidecar_invalid_client_auth.yaml        |   4 +-
 .../config/sidecar_invalid_file_permissions.yaml   |   4 +-
 .../resources/config/sidecar_live_migration.yaml   |   4 +-
 .../src/test/resources/config/sidecar_metrics.yaml |   4 +-
 .../config/sidecar_metrics_empty_filters.yaml      |   4 +-
 .../test/resources/config/sidecar_missing_jmx.yaml |   4 +-
 .../config/sidecar_multiple_instances.yaml         |   4 +-
 .../config/sidecar_no_local_instances.yaml         |   4 +-
 .../sidecar_schema_keyspace_configuration.yaml     |   4 +-
 .../resources/config/sidecar_single_instance.yaml  |   4 +-
 .../sidecar_single_instance_non_zero_port.yaml     |   4 +-
 server/src/test/resources/config/sidecar_ssl.yaml  |   4 +-
 .../config/sidecar_unrecognized_authenticator.yaml |   4 +-
 .../config/sidecar_unrecognized_authorizer.yaml    |   4 +-
 .../config/sidecar_validation_configuration.yaml   |   9 +-
 .../config/sidecar_vertx_filesystem_options.yaml   |   4 +-
 .../snapshots/AbstractSnapshotPathBuilderTest.java |   3 +-
 37 files changed, 900 insertions(+), 366 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 90d1f9c3..5d82fef6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
 0.3.0
 -----
+ * Fast Cassandra Input Validator (CASSSIDECAR-361)
  * Upgrade caffeine dependency (CASSSIDECAR-332)
  * Add Live Migration Status endpoint to persist Live Migration status and for 
safety (CASSSIDECAR-345)
  * Sidecar endpoint for draining a node (CASSSIDECAR-342)
diff --git a/conf/sidecar.yaml b/conf/sidecar.yaml
index 809181ab..57be2e78 100644
--- a/conf/sidecar.yaml
+++ b/conf/sidecar.yaml
@@ -375,6 +375,23 @@ metrics:
 #      value: "vertx.eventbus.*"              # exclude all metrics starts 
with vertx.eventbus
 
 cassandra_input_validation:
+  validator:
+    # Implementation to use for the validation of Casandra inputs. Out of the 
box, Cassandra Sidecar provides
+    # org.apache.cassandra.sidecar.utils.{RegexBasedCassandraInputValidator, 
FastCassandraInputValidator}.
+    #
+    # - RegexBasedCassandraInputValidator default implementation the uses 
regular expressions to perform validations
+    # - FastCassandraInputValidator optimized implementation that does not use 
regular expressions. This implementation
+    #                               ignores the regular expressions configured 
in the cassandra_input_validation
+    #                               configuration.
+  - class_name: 
org.apache.cassandra.sidecar.utils.RegexBasedCassandraInputValidator
+    # Configuration parameters that are only applicable to the 
FastCassandraInputValidator implementation
+    #parameters:
+    #  # Comma-separated list of terminations allowed for the component name. 
By default, allowed component
+    #  # names can only end in .db, .cql, .json, .crc32, or TOC.txt
+    #  valid_terminations: ".db,.cql,.json,.crc32,TOC.txt"
+    #  # Comma-separated list of terminations allowed for the restricted 
component name. By default, allowed
+    #  # restricted component names con only end in .db or TOC.txt
+    #  valid_restricted_terminations: ".db,TOC.txt"
   forbidden_keyspaces:
     - system_schema
     - system_traces
@@ -386,8 +403,8 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
 
 blob_restore:
   job_discovery_active_loop_delay: 5m
diff --git a/docs/src/user.adoc b/docs/src/user.adoc
index 8e78c951..d8ef90a7 100644
--- a/docs/src/user.adoc
+++ b/docs/src/user.adoc
@@ -402,11 +402,16 @@ The `metrics` configuration defines how Cassandra Sidecar 
exposes metrics over J
 
 This section defines input validations for Cassandra keyspace and directory 
names which are used for SSTable imports. The following properties are defined:
 
+* `validator`: The implementation to use for the validation of Casandra inputs.
+** `class_name`: The name of the class implementing the 
CassandraInputValidator interface. Out of the box Cassandra Sidecar provides 
org.apache.cassandra.sidecar.utils.{RegexBasedCassandraInputValidator, 
FastCassandraInputValidator}.
+** `parameters`: Configuration parameters that are only applicable to the 
FastCassandraInputValidator implementation.
+*** `valid_terminations`: Comma-separated list of terminations allowed for the 
component name.
+*** `valid_restricted_terminations`: Comma-separated list of terminations 
allowed for the restricted component name.git
 * `forbidden_keyspaces`: This is a list of keyspace names which are forbidden 
to be used for SSTable imports.
 * `allowed_chars_for_directory`: This is a regular expression which defines 
the characters that can be used in directory names used for SSTable imports. By 
default `"[a-zA-Z][a-zA-Z0-9_]{0,47}"`
 * `allowed_chars_for_quoted_name`: This is a regular expression which defines 
the characters that can be used in quoted names used for SSTable imports. If a 
quoted name does not match this regular expression, the SSTable import request 
will be rejected. By default, `"[a-zA-Z_0-9]{1,48}"`
-* `allowed_chars_for_component_name`: This is a regular expression which 
defines which characters can be used for SSTable component file names. By 
default, `"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"`.
-* `allowed_chars_for_restricted_component_name`: This is a regular expression 
which defines which characters can be used in the SSTable component file names 
for `.db` and `TOC.txt` files. By default, `"[a-zA-Z0-9_-]+(.db|TOC.txt)"`.
+* `allowed_chars_for_component_name`: This is a regular expression which 
defines which characters can be used for SSTable component file names. By 
default, `"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"`.
+* `allowed_chars_for_restricted_component_name`: This is a regular expression 
which defines which characters can be used in the SSTable component file names 
for `.db` and `TOC.txt` files. By default, `"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"`.
 
 [[blob-restore]]
 ### blob_restore
@@ -442,4 +447,4 @@ The `live_migration` section of the `sidecar.yaml` file is 
used to configure the
 
 * `files_to_exclude`: This is a list of files to not include when migrating 
between machines. Both glob and regex patterns can be used.
 * `dirs_to_exclude`: This is a list of directories to not include when 
migrating between machines. By default, `glob:${DATA_FILE_DIR}/*/*/snapshots`, 
to exclude snapshot directories from being migrated to the destination host.
-* `migration_map`: This is a map source to destination hostnames. For example 
`localhost1: localhost4` means that we will be migrating data from `localhost1` 
to `localhost4`.
\ No newline at end of file
+* `migration_map`: This is a map source to destination hostnames. For example 
`localhost1: localhost4` means that we will be migrating data from `localhost1` 
to `localhost4`.
diff --git a/examples/conf/sidecar-ccm.yaml b/examples/conf/sidecar-ccm.yaml
index bbd41e12..16f45096 100644
--- a/examples/conf/sidecar-ccm.yaml
+++ b/examples/conf/sidecar-ccm.yaml
@@ -433,8 +433,8 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
 
 blob_restore:
   job_discovery_active_loop_delay: 5m
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/CassandraInputValidationConfiguration.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/CassandraInputValidationConfiguration.java
index 98205a19..d77902d3 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/config/CassandraInputValidationConfiguration.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/CassandraInputValidationConfiguration.java
@@ -25,6 +25,11 @@ import java.util.Set;
  */
 public interface CassandraInputValidationConfiguration
 {
+    /**
+     * @return configuration needed to configure the {@link 
org.apache.cassandra.sidecar.utils.CassandraInputValidator}
+     */
+    ParameterizedClassConfiguration validatorConfiguration();
+
     /**
      * @return a set of forbidden keyspaces
      */
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/CassandraInputValidationConfigurationImpl.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/CassandraInputValidationConfigurationImpl.java
index 1538fac9..db8f4218 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/CassandraInputValidationConfigurationImpl.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/config/yaml/CassandraInputValidationConfigurationImpl.java
@@ -21,16 +21,22 @@ package org.apache.cassandra.sidecar.config.yaml;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import 
org.apache.cassandra.sidecar.config.CassandraInputValidationConfiguration;
+import org.apache.cassandra.sidecar.config.ParameterizedClassConfiguration;
+import org.apache.cassandra.sidecar.utils.RegexBasedCassandraInputValidator;
 
 /**
  * Encapsulate configuration values for validation properties used for 
Cassandra inputs
  */
 public class CassandraInputValidationConfigurationImpl implements 
CassandraInputValidationConfiguration
 {
+    public static final String VALIDATOR_PROPERTY = "validator";
+    private static final ParameterizedClassConfiguration 
DEFAULT_VALIDATOR_CONFIGURATION
+    = new 
ParameterizedClassConfigurationImpl(RegexBasedCassandraInputValidator.class.getName(),
 Map.of());
     public static final String FORBIDDEN_KEYSPACES_PROPERTY = 
"forbidden_keyspaces";
     public static final Set<String> DEFAULT_FORBIDDEN_KEYSPACES =
     Collections.unmodifiableSet(new HashSet<>(Arrays.asList("system_schema",
@@ -47,10 +53,13 @@ public class CassandraInputValidationConfigurationImpl 
implements CassandraInput
     public static final String DEFAULT_ALLOWED_CHARS_FOR_QUOTED_NAME = 
"[a-zA-Z_0-9]{1,48}";
     public static final String ALLOWED_CHARS_FOR_COMPONENT_NAME_PROPERTY = 
"allowed_chars_for_component_name";
     public static final String DEFAULT_ALLOWED_CHARS_FOR_COMPONENT_NAME =
-    "[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)";
+    "[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)";
     public static final String 
ALLOWED_CHARS_FOR_RESTRICTED_COMPONENT_NAME_PROPERTY =
     "allowed_chars_for_restricted_component_name";
-    public static final String 
DEFAULT_ALLOWED_CHARS_FOR_RESTRICTED_COMPONENT_NAME = 
"[a-zA-Z0-9_-]+(.db|TOC.txt)";
+    public static final String 
DEFAULT_ALLOWED_CHARS_FOR_RESTRICTED_COMPONENT_NAME = 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)";
+
+    @JsonProperty(value = VALIDATOR_PROPERTY)
+    protected final ParameterizedClassConfiguration validatorConfiguration;
 
     @JsonProperty(FORBIDDEN_KEYSPACES_PROPERTY)
     protected final Set<String> forbiddenKeyspaces;
@@ -69,19 +78,22 @@ public class CassandraInputValidationConfigurationImpl 
implements CassandraInput
 
     public CassandraInputValidationConfigurationImpl()
     {
-        this(DEFAULT_FORBIDDEN_KEYSPACES,
+        this(DEFAULT_VALIDATOR_CONFIGURATION,
+             DEFAULT_FORBIDDEN_KEYSPACES,
              DEFAULT_ALLOWED_CHARS_FOR_NAME,
              DEFAULT_ALLOWED_CHARS_FOR_QUOTED_NAME,
              DEFAULT_ALLOWED_CHARS_FOR_COMPONENT_NAME,
              DEFAULT_ALLOWED_CHARS_FOR_RESTRICTED_COMPONENT_NAME);
     }
 
-    public CassandraInputValidationConfigurationImpl(Set<String> 
forbiddenKeyspaces,
+    public 
CassandraInputValidationConfigurationImpl(ParameterizedClassConfiguration 
validatorConfiguration,
+                                                     Set<String> 
forbiddenKeyspaces,
                                                      String 
allowedPatternForName,
                                                      String 
allowedPatternForQuotedName,
                                                      String 
allowedPatternForComponentName,
                                                      String 
allowedPatternForRestrictedComponentName)
     {
+        this.validatorConfiguration = validatorConfiguration;
         this.forbiddenKeyspaces = forbiddenKeyspaces;
         this.allowedPatternForName = allowedPatternForName;
         this.allowedPatternForQuotedName = allowedPatternForQuotedName;
@@ -89,6 +101,16 @@ public class CassandraInputValidationConfigurationImpl 
implements CassandraInput
         this.allowedPatternForRestrictedComponentName = 
allowedPatternForRestrictedComponentName;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @JsonProperty(value = VALIDATOR_PROPERTY)
+    public ParameterizedClassConfiguration validatorConfiguration()
+    {
+        return validatorConfiguration;
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/exceptions/CassandraInputException.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/exceptions/CassandraInputException.java
new file mode 100644
index 00000000..f028d515
--- /dev/null
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/exceptions/CassandraInputException.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.exceptions;
+
+/**
+ * Exception thrown when a Cassandra input is invalid
+ */
+public class CassandraInputException extends IllegalArgumentException
+{
+    public CassandraInputException(String message)
+    {
+        super(message);
+    }
+}
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/exceptions/ForbiddenCassandraInputException.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/exceptions/ForbiddenCassandraInputException.java
new file mode 100644
index 00000000..8a671535
--- /dev/null
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/exceptions/ForbiddenCassandraInputException.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.exceptions;
+
+/**
+ * Exception thrown when a Cassandra input is forbidden
+ */
+public class ForbiddenCassandraInputException extends CassandraInputException
+{
+    public ForbiddenCassandraInputException(String message)
+    {
+        super(message);
+    }
+}
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/handlers/AbstractHandler.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/handlers/AbstractHandler.java
index a7c4f7f6..7060a3b3 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/handlers/AbstractHandler.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/handlers/AbstractHandler.java
@@ -34,6 +34,7 @@ import 
org.apache.cassandra.sidecar.common.server.data.QualifiedTableName;
 import 
org.apache.cassandra.sidecar.common.server.exceptions.JmxAuthenticationException;
 import org.apache.cassandra.sidecar.common.utils.Preconditions;
 import org.apache.cassandra.sidecar.concurrent.ExecutorPools;
+import 
org.apache.cassandra.sidecar.exceptions.ForbiddenCassandraInputException;
 import 
org.apache.cassandra.sidecar.exceptions.NoSuchCassandraInstanceException;
 import org.apache.cassandra.sidecar.utils.CassandraInputValidator;
 import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher;
@@ -217,6 +218,11 @@ public abstract class AbstractHandler<T> implements 
Handler<RoutingContext>
             return wrapHttpException(HttpResponseStatus.MISDIRECTED_REQUEST, 
cause.getMessage(), cause);
         }
 
+        if (cause instanceof ForbiddenCassandraInputException)
+        {
+            return wrapHttpException(HttpResponseStatus.FORBIDDEN, 
cause.getMessage());
+        }
+
         if (cause instanceof IllegalArgumentException)
         {
             return wrapHttpException(HttpResponseStatus.BAD_REQUEST, 
cause.getMessage(), cause);
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/modules/UtilitiesModule.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/modules/UtilitiesModule.java
index 858bc5ba..f7dc3430 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/modules/UtilitiesModule.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/modules/UtilitiesModule.java
@@ -25,9 +25,14 @@ import com.google.inject.name.Named;
 import org.apache.cassandra.sidecar.common.server.dns.DnsResolver;
 import org.apache.cassandra.sidecar.common.server.utils.DriverUtils;
 import org.apache.cassandra.sidecar.common.server.utils.SidecarVersionProvider;
+import 
org.apache.cassandra.sidecar.config.CassandraInputValidationConfiguration;
 import org.apache.cassandra.sidecar.config.SidecarConfiguration;
+import org.apache.cassandra.sidecar.exceptions.ConfigurationException;
+import org.apache.cassandra.sidecar.utils.CassandraInputValidator;
 import org.apache.cassandra.sidecar.utils.DigestAlgorithmProvider;
+import org.apache.cassandra.sidecar.utils.FastCassandraInputValidator;
 import org.apache.cassandra.sidecar.utils.JdkMd5DigestProvider;
+import org.apache.cassandra.sidecar.utils.RegexBasedCassandraInputValidator;
 import org.apache.cassandra.sidecar.utils.TimeProvider;
 import org.apache.cassandra.sidecar.utils.XXHash32Provider;
 
@@ -82,4 +87,26 @@ public class UtilitiesModule extends AbstractModule
     {
         return new SidecarVersionProvider("/sidecar.version");
     }
+
+    @Provides
+    @Singleton
+    CassandraInputValidator 
cassandraInputValidatorFactory(SidecarConfiguration configuration)
+    {
+        CassandraInputValidationConfiguration config = 
configuration.cassandraInputValidationConfiguration();
+
+        if (config.validatorConfiguration() == null
+            || config.validatorConfiguration().className() == null
+            || 
RegexBasedCassandraInputValidator.class.getName().equals(config.validatorConfiguration().className()))
+        {
+            // When the validator configuration is not set assume legacy 
configuration
+            // and provide the regex-based validator.
+            return new RegexBasedCassandraInputValidator(config);
+        }
+        else if 
(FastCassandraInputValidator.class.getName().equals(config.validatorConfiguration().className()))
+        {
+            return new FastCassandraInputValidator(config);
+        }
+
+        throw new ConfigurationException("Unrecognized validator provider " + 
config.validatorConfiguration().className() + " configured");
+    }
 }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/snapshots/SnapshotPathBuilder.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/snapshots/SnapshotPathBuilder.java
index fd5e561a..80a9f279 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/snapshots/SnapshotPathBuilder.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/snapshots/SnapshotPathBuilder.java
@@ -37,7 +37,6 @@ import com.google.inject.Singleton;
 import io.vertx.core.Future;
 import io.vertx.core.Vertx;
 import org.apache.cassandra.sidecar.cluster.InstancesMetadata;
-import org.apache.cassandra.sidecar.common.utils.Preconditions;
 import org.apache.cassandra.sidecar.concurrent.ExecutorPools;
 import 
org.apache.cassandra.sidecar.handlers.data.StreamSSTableComponentRequestParam;
 import org.apache.cassandra.sidecar.utils.BaseFileSystem;
@@ -57,10 +56,10 @@ public class SnapshotPathBuilder extends BaseFileSystem
      * Creates a new SnapshotPathBuilder for snapshots of an instance with the 
given {@code vertx} instance and
      * {@code instancesMetadata Cassandra configuration}.
      *
-     * @param vertx           the vertx instance
+     * @param vertx             the vertx instance
      * @param instancesMetadata the configuration for Cassandra
-     * @param validator       a validator instance to validate 
Cassandra-specific input
-     * @param executorPools   executor pools for blocking executions
+     * @param validator         a validator instance to validate 
Cassandra-specific input
+     * @param executorPools     executor pools for blocking executions
      */
     @Inject
     public SnapshotPathBuilder(Vertx vertx,
@@ -158,15 +157,12 @@ public class SnapshotPathBuilder extends BaseFileSystem
             validator.validateTableId(request.tableId());
         }
         validator.validateSnapshotName(request.snapshotName());
-        // Only allow .db and TOC.txt components here
         String secondaryIndexName = request.secondaryIndexName();
         if (secondaryIndexName != null)
         {
-            Preconditions.checkArgument(!secondaryIndexName.isEmpty(), 
"secondaryIndexName cannot be empty");
-            Preconditions.checkArgument(secondaryIndexName.charAt(0) == '.', 
"Invalid secondary index name");
-            String indexName = secondaryIndexName.substring(1);
-            validator.validatePattern(indexName, indexName, "secondary index", 
false);
+            validator.validateIndexName(secondaryIndexName);
         }
+        // Only allow .db and TOC.txt components here
         validator.validateRestrictedComponentName(request.componentName());
     }
 
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/utils/CassandraInputValidator.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/utils/CassandraInputValidator.java
index 94e7c9f9..affdcc90 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/utils/CassandraInputValidator.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/utils/CassandraInputValidator.java
@@ -18,45 +18,15 @@
 
 package org.apache.cassandra.sidecar.utils;
 
-import java.io.File;
-import java.util.Objects;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import io.netty.handler.codec.http.HttpResponseStatus;
-import io.vertx.ext.web.handler.HttpException;
 import org.apache.cassandra.sidecar.common.server.data.Name;
-import org.apache.cassandra.sidecar.common.utils.Preconditions;
-import 
org.apache.cassandra.sidecar.config.CassandraInputValidationConfiguration;
-import 
org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl;
+import org.apache.cassandra.sidecar.exceptions.CassandraInputException;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.VisibleForTesting;
 
 /**
- * Miscellaneous methods used for validation.
+ * Interface that defines different Cassandra input validations
  */
-@Singleton
-public class CassandraInputValidator
+public interface CassandraInputValidator
 {
-    private final CassandraInputValidationConfiguration 
validationConfiguration;
-
-    /**
-     * Constructs a new object with the provided {@code 
validationConfiguration}
-     *
-     * @param validationConfiguration a validation configuration
-     */
-    @Inject
-    public CassandraInputValidator(CassandraInputValidationConfiguration 
validationConfiguration)
-    {
-        this.validationConfiguration = validationConfiguration;
-    }
-
-    @VisibleForTesting
-    public CassandraInputValidator()
-    {
-        this(new CassandraInputValidationConfigurationImpl());
-    }
-
     /**
      * Validates that the {@code keyspace} is not {@code null}, that it 
contains valid characters, and that it's
      * not a forbidden keyspace.
@@ -64,19 +34,8 @@ public class CassandraInputValidator
      * @param keyspace the name of the Cassandra keyspace to validate
      * @return the validated {@code keyspace}
      * @throws NullPointerException when the {@code keyspace} is {@code null}
-     * @throws HttpException        when the {@code keyspace} contains invalid 
characters in the name or when the
-     *                              keyspace is forbidden
      */
-    public Name validateKeyspaceName(@NotNull String keyspace)
-    {
-        Name name = new Name(keyspace);
-        validateNamePattern(name, "keyspace");
-
-        if (validationConfiguration.forbiddenKeyspaces().contains(name.name()))
-            throw new HttpException(HttpResponseStatus.FORBIDDEN.code(), 
"Forbidden keyspace: " + keyspace);
-
-        return name;
-    }
+    Name validateKeyspaceName(@NotNull String keyspace) throws 
NullPointerException;
 
     /**
      * Validates that the {@code tableName} is not {@code null}, and it 
contains allowed character for Cassandra
@@ -84,15 +43,10 @@ public class CassandraInputValidator
      *
      * @param tableName the name of the Cassandra table to validate
      * @return the validated {@code tableName}
-     * @throws NullPointerException when the {@code tableName} is {@code null}
-     * @throws HttpException        when the {@code tableName} contains 
invalid characters in the name
+     * @throws NullPointerException    when the {@code tableName} is {@code 
null}
+     * @throws CassandraInputException when the {@code tableName} contains 
invalid characters in the name
      */
-    public Name validateTableName(@NotNull String tableName)
-    {
-        Name name = new Name(tableName);
-        validateNamePattern(name, "table name");
-        return name;
-    }
+    Name validateTableName(@NotNull String tableName);
 
     /**
      * Validates that the {@code snapshotName} is not {@code null}, and it 
contains allowed character for the
@@ -100,18 +54,10 @@ public class CassandraInputValidator
      *
      * @param snapshotName the name of the Cassandra snapshot to validate
      * @return the validated {@code snapshotName}
-     * @throws NullPointerException when the {@code snapshotName} is {@code 
null}
-     * @throws HttpException        when the {@code snapshotName} contains 
invalid characters in the name
+     * @throws NullPointerException    when the {@code snapshotName} is {@code 
null}
+     * @throws CassandraInputException when the {@code snapshotName} contains 
invalid characters in the name
      */
-    public String validateSnapshotName(@NotNull String snapshotName)
-    {
-        Objects.requireNonNull(snapshotName, "snapshotName must not be null");
-        //  most UNIX systems only disallow file separator and null characters 
for directory names
-        if (snapshotName.contains(File.separator) || 
snapshotName.contains("\0"))
-            throw new HttpException(HttpResponseStatus.BAD_REQUEST.code(),
-                                    "Invalid characters in snapshot name: " + 
snapshotName);
-        return snapshotName;
-    }
+    String validateSnapshotName(@NotNull String snapshotName);
 
     /**
      * Validates that the {@code componentName} is not {@code null}, and it 
contains allowed names for the
@@ -119,14 +65,10 @@ public class CassandraInputValidator
      *
      * @param componentName the name of the SSTable component to validate
      * @return the validated {@code componentName}
-     * @throws NullPointerException when the {@code componentName} is null
-     * @throws HttpException        when the {@code componentName} is not valid
+     * @throws NullPointerException    when the {@code componentName} is null
+     * @throws CassandraInputException when the {@code componentName} is not 
valid
      */
-    public String validateComponentName(@NotNull String componentName)
-    {
-        return validateComponentNameByRegex(componentName,
-                                            
validationConfiguration.allowedPatternForComponentName());
-    }
+    String validateComponentName(@NotNull String componentName);
 
     /**
      * Validates that the {@code componentName} is not {@code null}, and it 
contains a subset of allowed names for the
@@ -134,94 +76,32 @@ public class CassandraInputValidator
      *
      * @param componentName the name of the SSTable component to validate
      * @return the validated {@code componentName}
-     * @throws NullPointerException when the {@code componentName} is null
-     * @throws HttpException        when the {@code componentName} is not a 
valid name for the configured restricted
-     *                              component name
+     * @throws NullPointerException    when the {@code componentName} is null
+     * @throws CassandraInputException when the {@code componentName} is not a 
valid name for the configured restricted
+     *                                 component name
      */
-    public String validateRestrictedComponentName(@NotNull String 
componentName)
-    {
-        return validateComponentNameByRegex(componentName,
-                                            
validationConfiguration.allowedPatternForRestrictedComponentName());
-    }
+    String validateRestrictedComponentName(@NotNull String componentName);
 
     /**
-     * Validates the {@code componentName} against the provided {@code regex}.
+     * Validates that the index name has only valid characters
      *
-     * @param componentName the name of the SSTable component
-     * @param regex         the regex for validation
-     * @return the validated {@code componentName}
-     * @throws NullPointerException when the {@code componentName} is null
-     * @throws HttpException        when the {@code componentName} does not 
match the provided regex
+     * @param secondaryIndexName the name of the secondary index
      */
-    @NotNull
-    private String validateComponentNameByRegex(String componentName, String 
regex)
-    {
-        Objects.requireNonNull(componentName, "componentName must not be 
null");
-        if (!componentName.matches(regex))
-            throw new HttpException(HttpResponseStatus.BAD_REQUEST.code(),
-                                    "Invalid component name: " + 
componentName);
-        return componentName;
-    }
-
-    /**
-     * Validates that the {@code unquotedInput} matches the {@code 
patternWordChars}
-     *
-     * @param unquotedInput      the unquoted input
-     * @param maybeQuoted        the original input used for the exception 
message
-     * @param exceptionHint      hint to add in the exception message
-     * @param isQuotedFromSource whether the name was quoted from source
-     * @throws HttpException when the {@code unquotedInput} does not match the 
pattern
-     */
-    public void validatePattern(String unquotedInput, String maybeQuoted,
-                                String exceptionHint, boolean 
isQuotedFromSource)
-    {
-        String pattern = isQuotedFromSource
-                         ? 
validationConfiguration.allowedPatternForQuotedName()
-                         : validationConfiguration.allowedPatternForName();
-
-        if (!unquotedInput.matches(pattern))
-            throw new HttpException(HttpResponseStatus.BAD_REQUEST.code(),
-                                    "Invalid characters in " + exceptionHint + 
": " + maybeQuoted);
-    }
+    void validateIndexName(String secondaryIndexName);
 
     /**
      * Validates that the unique table identifier is a valid hexadecimal
      *
      * @param tableId the table identifier to validate
      */
-    public void validateTableId(String tableId)
-    {
-        Objects.requireNonNull(tableId, "tableId must not be null");
-        Preconditions.checkArgument(tableId.length() <= 32, "tableId cannot be 
longer than 32 characters");
-        for (int i = 0; i < tableId.length(); i++)
-        {
-            char c = tableId.charAt(i);
-            if (!isHex(c))
-                throw new HttpException(HttpResponseStatus.BAD_REQUEST.code(),
-                                        "Invalid characters in table id: " + 
tableId);
-        }
-    }
-
-    /**
-     * @param c the character to test
-     * @return {@code true} if the input {@code c} is valid hexadecimal, 
{@code false} otherwise
-     */
-    protected boolean isHex(char c)
-    {
-        return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9') || (c >= 'A' 
&& c <= 'F');
-    }
+    void validateTableId(String tableId);
 
     /**
-     * Removes the surrounding quotes for the name, if the quotes are present. 
Otherwise, returns the original
-     * input.
-     * Validates that the {@code name} matches the {@code patternWordChars}
+     * Validates that the {@code name} matches the name pattern
      *
-     * @param name               name
-     * @param exceptionHint      hint to add in the exception message
-     * @throws HttpException when the {@code unquotedInput} does not match the 
pattern
+     * @param name          name
+     * @param exceptionHint hint to add in the exception message
+     * @throws CassandraInputException when the {@code unquotedInput} does not 
match the pattern
      */
-    public void validateNamePattern(Name name, String exceptionHint)
-    {
-        validatePattern(name.name(), name.maybeQuotedName(), exceptionHint, 
name.isSourceQuoted());
-    }
+    void validateNamePattern(Name name, String exceptionHint);
 }
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/utils/FastCassandraInputValidator.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/utils/FastCassandraInputValidator.java
new file mode 100644
index 00000000..99a0f70b
--- /dev/null
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/utils/FastCassandraInputValidator.java
@@ -0,0 +1,314 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.utils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.cassandra.sidecar.common.server.data.Name;
+import org.apache.cassandra.sidecar.common.utils.Preconditions;
+import 
org.apache.cassandra.sidecar.config.CassandraInputValidationConfiguration;
+import 
org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl;
+import org.apache.cassandra.sidecar.exceptions.CassandraInputException;
+import 
org.apache.cassandra.sidecar.exceptions.ForbiddenCassandraInputException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.VisibleForTesting;
+
+/**
+ * An implementation of the {@link CassandraInputValidator} that does not use 
regular expressions
+ * for validations and uses optimized validations.
+ */
+public class FastCassandraInputValidator extends 
RegexBasedCassandraInputValidator
+{
+    /**
+     * Longest permissible keyspace name
+     */
+    public static final int KEYSPACE_NAME_LENGTH = 48;
+    /**
+     * Longest permissible table name. See CASSANDRA-20389 (Create table fails 
on long table names) for
+     * details about the maximum length for table names.
+     */
+    public static final int TABLE_NAME_LENGTH = 222;
+    /**
+     * Default valid component name terminations
+     */
+    public static final List<String> DEFAULT_VALID_TERMINATIONS = 
List.of(".db", ".cql", ".json", ".crc32", "TOC.txt");
+
+    /**
+     * Default valid component name terminations for restricted component names
+     */
+    public static final List<String> DEFAULT_VALID_RESTRICTED_TERMINATIONS = 
List.of(".db", "TOC.txt");
+
+    @VisibleForTesting
+    final List<String> validTerminations;
+    @VisibleForTesting
+    final List<String> validRestrictedTerminations;
+
+    @VisibleForTesting
+    public FastCassandraInputValidator()
+    {
+        this(new CassandraInputValidationConfigurationImpl());
+    }
+
+    /**
+     * Constructs a new object with the provided {@code 
validationConfiguration}
+     *
+     * @param validationConfiguration a validation configuration
+     */
+    public FastCassandraInputValidator(CassandraInputValidationConfiguration 
validationConfiguration)
+    {
+        super(validationConfiguration);
+        Map<String, String> configMap = 
validationConfiguration.validatorConfiguration().namedParameters();
+        validTerminations = parseConfiguredOrDefault(configMap, 
"valid_terminations", DEFAULT_VALID_TERMINATIONS);
+        validRestrictedTerminations = parseConfiguredOrDefault(configMap, 
"valid_restricted_terminations", DEFAULT_VALID_RESTRICTED_TERMINATIONS);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Name validateKeyspaceName(@NotNull String keyspace) throws 
NullPointerException
+    {
+        Name name = new Name(keyspace);
+        validateNameLength(name, "keyspace", KEYSPACE_NAME_LENGTH);
+        validateNamePattern(name, "keyspace");
+
+        if (validationConfiguration.forbiddenKeyspaces().contains(name.name()))
+            throw new ForbiddenCassandraInputException("Forbidden keyspace: " 
+ keyspace);
+
+        return name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Name validateTableName(@NotNull String tableName)
+    {
+        Name name = new Name(tableName);
+        validateNameLength(name, "table name", TABLE_NAME_LENGTH);
+        validateNamePattern(name, "table name");
+        return name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String validateComponentName(@NotNull String componentName)
+    {
+        Objects.requireNonNull(componentName, "componentName must not be 
null");
+        Preconditions.checkArgument(!componentName.isEmpty(), () -> 
"componentName cannot be empty");
+        validateComponentName(componentName, validTerminations);
+        return componentName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String validateRestrictedComponentName(@NotNull String 
componentName)
+    {
+        Objects.requireNonNull(componentName, "componentName must not be 
null");
+        Preconditions.checkArgument(!componentName.isEmpty(), () -> 
"componentName cannot be empty");
+        validateComponentName(componentName, validRestrictedTerminations);
+        return componentName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void validateIndexName(String secondaryIndexName)
+    {
+        Preconditions.checkArgument(!secondaryIndexName.isEmpty(), 
"secondaryIndexName cannot be empty");
+        if (secondaryIndexName.charAt(0) != '.')
+            throw new CassandraInputException("Invalid secondary index name: " 
+ secondaryIndexName);
+        validateNamePattern(secondaryIndexName, secondaryIndexName, false, 
"secondary index", 1 /* skip the first character */);
+    }
+
+    /**
+     * Validates that the {@code name} is a valid name in Cassandra as defined 
by the grammar in
+     * <a 
href="https://cassandra.apache.org/doc/4.1/cassandra/cql/ddl.html#common-definitions";>Cassandra
 CQL common
+     * definitions</a>
+     *
+     * @param name          name to validate
+     * @param exceptionHint hint to add in the exception message
+     * @throws CassandraInputException when the {@code unquotedInput} has 
invalid characters
+     */
+    @Override
+    public void validateNamePattern(Name name, String exceptionHint)
+    {
+        validateNamePattern(name.name(), name.maybeQuotedName(), 
name.isSourceQuoted(), exceptionHint, 0);
+    }
+
+    /**
+     * Validates that the {@code name} is a valid name in Cassandra as defined 
by the grammar in
+     * <a 
href="https://cassandra.apache.org/doc/4.1/cassandra/cql/ddl.html#common-definitions";>Cassandra
 CQL common
+     * definitions</a>. The validation will only take into account the start 
index.
+     *
+     * @param unquotedName    the unquoted name to validate
+     * @param maybeQuotedName the name that maybe quoted
+     * @param isSourceQuoted  whether the source will be quoted
+     * @param exceptionHint   hint to add in the exception message
+     * @param startIndex      start index
+     * @throws CassandraInputException when the {@code unquotedName} has 
invalid characters
+     */
+    protected void validateNamePattern(String unquotedName, String 
maybeQuotedName, boolean isSourceQuoted,
+                                       String exceptionHint, int startIndex)
+    {
+        char c;
+        if (!isSourceQuoted)
+        {
+            // Validate the first character. Unquoted names can only begin 
with a letter
+            c = unquotedName.charAt(startIndex++);
+            if (!isLetter(c))
+                throw new CassandraInputException("Invalid characters in " + 
exceptionHint + ": " + maybeQuotedName);
+        }
+
+        while (startIndex < unquotedName.length())
+        {
+            c = unquotedName.charAt(startIndex++);
+            if (!isAlphanumeric(c) && !isUnderscore(c))
+                throw new CassandraInputException("Invalid characters in " + 
exceptionHint + ": " + maybeQuotedName);
+        }
+    }
+
+    /**
+     * Validates that the {@code name} has valid length
+     *
+     * @param name          name to validate
+     * @param exceptionHint hint to add in the exception message
+     * @param maxNameLength the maximum length for the name
+     * @throws CassandraInputException when the length of the {@code 
unquotedInput} is empty or larger than
+     *                                 {@code maxNameLength}
+     */
+    protected void validateNameLength(Name name, String exceptionHint, int 
maxNameLength)
+    {
+        String unquotedInput = name.name();
+        if (unquotedInput.isEmpty() || unquotedInput.length() > maxNameLength)
+            throw new CassandraInputException("Invalid length " + 
unquotedInput.length() +
+                                              " for " + exceptionHint + ": " + 
name.maybeQuotedName());
+    }
+
+    /**
+     * Validates that the {@code componentName} has valid characters, and it 
ends with one of the
+     * {@code validTerminations}.
+     *
+     * @param componentName     the name of the component to validate
+     * @param validTerminations a list of valid terminations for the component 
name
+     */
+    protected void validateComponentName(String componentName, List<String> 
validTerminations)
+    {
+        char c;
+        int lastIndexOfAllowedTermination = 
lastIndexOfAllowedTermination(componentName, validTerminations);
+
+        if (lastIndexOfAllowedTermination < 1)
+            throw new CassandraInputException("Invalid component name: " + 
componentName);
+
+        for (int i = lastIndexOfAllowedTermination - 1; i >= 0; i--)
+        {
+            c = componentName.charAt(i);
+            if (!isValidComponentNameCharacter(c))
+                throw new CassandraInputException("Invalid component name: " + 
componentName);
+        }
+    }
+
+    /**
+     * @param componentName     the name of the component to validate
+     * @param validTerminations a list of valid terminations for the component 
name
+     * @return the last index of the first found allowed termination from the 
provided list of
+     * {@code validTerminations}, or {@code -1} if no index is found in any of 
the {@code validTerminations}
+     */
+    protected int lastIndexOfAllowedTermination(String componentName, 
List<String> validTerminations)
+    {
+        for (String allowedExtension : validTerminations)
+        {
+            if (componentName.endsWith(allowedExtension))
+                return componentName.length() - allowedExtension.length();
+        }
+        return -1;
+    }
+
+    /**
+     * @param c the character to test
+     * @return {@code true} if the input {@code c} is a valid alphanumeric 
character, underscore, or a dash;
+     * {@code false} otherwise
+     */
+    protected boolean isValidComponentNameCharacter(char c)
+    {
+        return isAlphanumeric(c) || isUnderscore(c) || isDash(c);
+    }
+
+    /**
+     * @param c the character to test
+     * @return {@code true} if the input {@code c} is a valid alphanumeric 
character, {@code false} otherwise
+     */
+    protected boolean isAlphanumeric(char c)
+    {
+        return (c >= '0' && c <= '9') || isLetter(c);
+    }
+
+    /**
+     * @param c the character to test
+     * @return {@code true} if the input {@code c} is a valid letter, {@code 
false} otherwise
+     */
+    protected boolean isLetter(char c)
+    {
+        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+    }
+
+    /**
+     * @param c the character to test
+     * @return {@code true} if the input {@code c} is an underscore, {@code 
false} otherwise
+     */
+    protected boolean isUnderscore(char c)
+    {
+        return c == '_';
+    }
+
+    /**
+     * @param c the character to test
+     * @return {@code true} if the input {@code c} is an underscore, {@code 
false} otherwise
+     */
+    protected boolean isDash(char c)
+    {
+        return c == '-';
+    }
+
+    /**
+     * @param configMap    the configuration map
+     * @param key          the key in the map
+     * @param defaultValue the default values to provide when the value is not 
available for parsing
+     * @return the parsed value, or the default value when unavailable
+     */
+    static List<String> parseConfiguredOrDefault(Map<String, String> 
configMap, String key, List<String> defaultValue)
+    {
+        if (configMap != null)
+        {
+            String value = configMap.get(key);
+            if (value != null && !value.isEmpty())
+            {
+                return List.of(value.split(","));
+            }
+        }
+        return defaultValue;
+    }
+}
diff --git 
a/server/src/main/java/org/apache/cassandra/sidecar/utils/CassandraInputValidator.java
 
b/server/src/main/java/org/apache/cassandra/sidecar/utils/RegexBasedCassandraInputValidator.java
similarity index 50%
copy from 
server/src/main/java/org/apache/cassandra/sidecar/utils/CassandraInputValidator.java
copy to 
server/src/main/java/org/apache/cassandra/sidecar/utils/RegexBasedCassandraInputValidator.java
index 94e7c9f9..4de8bf5a 100644
--- 
a/server/src/main/java/org/apache/cassandra/sidecar/utils/CassandraInputValidator.java
+++ 
b/server/src/main/java/org/apache/cassandra/sidecar/utils/RegexBasedCassandraInputValidator.java
@@ -21,72 +21,58 @@ package org.apache.cassandra.sidecar.utils;
 import java.io.File;
 import java.util.Objects;
 
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import io.netty.handler.codec.http.HttpResponseStatus;
-import io.vertx.ext.web.handler.HttpException;
 import org.apache.cassandra.sidecar.common.server.data.Name;
 import org.apache.cassandra.sidecar.common.utils.Preconditions;
 import 
org.apache.cassandra.sidecar.config.CassandraInputValidationConfiguration;
 import 
org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl;
+import org.apache.cassandra.sidecar.exceptions.CassandraInputException;
+import 
org.apache.cassandra.sidecar.exceptions.ForbiddenCassandraInputException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.VisibleForTesting;
 
 /**
  * Miscellaneous methods used for validation.
  */
-@Singleton
-public class CassandraInputValidator
+public class RegexBasedCassandraInputValidator implements 
CassandraInputValidator
 {
-    private final CassandraInputValidationConfiguration 
validationConfiguration;
+    protected final CassandraInputValidationConfiguration 
validationConfiguration;
+
+    @VisibleForTesting
+    RegexBasedCassandraInputValidator()
+    {
+        this(new CassandraInputValidationConfigurationImpl());
+    }
 
     /**
      * Constructs a new object with the provided {@code 
validationConfiguration}
      *
      * @param validationConfiguration a validation configuration
      */
-    @Inject
-    public CassandraInputValidator(CassandraInputValidationConfiguration 
validationConfiguration)
+    public 
RegexBasedCassandraInputValidator(CassandraInputValidationConfiguration 
validationConfiguration)
     {
         this.validationConfiguration = validationConfiguration;
     }
 
-    @VisibleForTesting
-    public CassandraInputValidator()
-    {
-        this(new CassandraInputValidationConfigurationImpl());
-    }
-
     /**
-     * Validates that the {@code keyspace} is not {@code null}, that it 
contains valid characters, and that it's
-     * not a forbidden keyspace.
-     *
-     * @param keyspace the name of the Cassandra keyspace to validate
-     * @return the validated {@code keyspace}
-     * @throws NullPointerException when the {@code keyspace} is {@code null}
-     * @throws HttpException        when the {@code keyspace} contains invalid 
characters in the name or when the
-     *                              keyspace is forbidden
+     * {@inheritDoc}
      */
+    @Override
     public Name validateKeyspaceName(@NotNull String keyspace)
     {
         Name name = new Name(keyspace);
-        validateNamePattern(name, "keyspace");
 
         if (validationConfiguration.forbiddenKeyspaces().contains(name.name()))
-            throw new HttpException(HttpResponseStatus.FORBIDDEN.code(), 
"Forbidden keyspace: " + keyspace);
+            throw new ForbiddenCassandraInputException("Forbidden keyspace: " 
+ keyspace);
+
+        validateNamePattern(name, "keyspace");
 
         return name;
     }
 
     /**
-     * Validates that the {@code tableName} is not {@code null}, and it 
contains allowed character for Cassandra
-     * table names.
-     *
-     * @param tableName the name of the Cassandra table to validate
-     * @return the validated {@code tableName}
-     * @throws NullPointerException when the {@code tableName} is {@code null}
-     * @throws HttpException        when the {@code tableName} contains 
invalid characters in the name
+     * {@inheritDoc}
      */
+    @Override
     public Name validateTableName(@NotNull String tableName)
     {
         Name name = new Name(tableName);
@@ -95,33 +81,22 @@ public class CassandraInputValidator
     }
 
     /**
-     * Validates that the {@code snapshotName} is not {@code null}, and it 
contains allowed character for the
-     * Cassandra snapshot names.
-     *
-     * @param snapshotName the name of the Cassandra snapshot to validate
-     * @return the validated {@code snapshotName}
-     * @throws NullPointerException when the {@code snapshotName} is {@code 
null}
-     * @throws HttpException        when the {@code snapshotName} contains 
invalid characters in the name
+     * {@inheritDoc}
      */
+    @Override
     public String validateSnapshotName(@NotNull String snapshotName)
     {
         Objects.requireNonNull(snapshotName, "snapshotName must not be null");
         //  most UNIX systems only disallow file separator and null characters 
for directory names
         if (snapshotName.contains(File.separator) || 
snapshotName.contains("\0"))
-            throw new HttpException(HttpResponseStatus.BAD_REQUEST.code(),
-                                    "Invalid characters in snapshot name: " + 
snapshotName);
+            throw new CassandraInputException("Invalid characters in snapshot 
name: " + snapshotName);
         return snapshotName;
     }
 
     /**
-     * Validates that the {@code componentName} is not {@code null}, and it 
contains allowed names for the
-     * Cassandra SSTable component.
-     *
-     * @param componentName the name of the SSTable component to validate
-     * @return the validated {@code componentName}
-     * @throws NullPointerException when the {@code componentName} is null
-     * @throws HttpException        when the {@code componentName} is not valid
+     * {@inheritDoc}
      */
+    @Override
     public String validateComponentName(@NotNull String componentName)
     {
         return validateComponentNameByRegex(componentName,
@@ -129,15 +104,9 @@ public class CassandraInputValidator
     }
 
     /**
-     * Validates that the {@code componentName} is not {@code null}, and it 
contains a subset of allowed names for the
-     * Cassandra SSTable component.
-     *
-     * @param componentName the name of the SSTable component to validate
-     * @return the validated {@code componentName}
-     * @throws NullPointerException when the {@code componentName} is null
-     * @throws HttpException        when the {@code componentName} is not a 
valid name for the configured restricted
-     *                              component name
+     * {@inheritDoc}
      */
+    @Override
     public String validateRestrictedComponentName(@NotNull String 
componentName)
     {
         return validateComponentNameByRegex(componentName,
@@ -145,50 +114,33 @@ public class CassandraInputValidator
     }
 
     /**
-     * Validates the {@code componentName} against the provided {@code regex}.
-     *
-     * @param componentName the name of the SSTable component
-     * @param regex         the regex for validation
-     * @return the validated {@code componentName}
-     * @throws NullPointerException when the {@code componentName} is null
-     * @throws HttpException        when the {@code componentName} does not 
match the provided regex
+     * {@inheritDoc}
      */
-    @NotNull
-    private String validateComponentNameByRegex(String componentName, String 
regex)
+    @Override
+    public void validateIndexName(String secondaryIndexName)
     {
-        Objects.requireNonNull(componentName, "componentName must not be 
null");
-        if (!componentName.matches(regex))
-            throw new HttpException(HttpResponseStatus.BAD_REQUEST.code(),
-                                    "Invalid component name: " + 
componentName);
-        return componentName;
+        Preconditions.checkArgument(!secondaryIndexName.isEmpty(), 
"secondaryIndexName cannot be empty");
+        Preconditions.checkArgument(secondaryIndexName.charAt(0) == '.', 
"Invalid secondary index name");
+        String indexName = secondaryIndexName.substring(1);
+        validatePattern(indexName, indexName, "secondary index", false);
     }
 
     /**
-     * Validates that the {@code unquotedInput} matches the {@code 
patternWordChars}
-     *
-     * @param unquotedInput      the unquoted input
-     * @param maybeQuoted        the original input used for the exception 
message
-     * @param exceptionHint      hint to add in the exception message
-     * @param isQuotedFromSource whether the name was quoted from source
-     * @throws HttpException when the {@code unquotedInput} does not match the 
pattern
+     * {@inheritDoc}
      */
-    public void validatePattern(String unquotedInput, String maybeQuoted,
-                                String exceptionHint, boolean 
isQuotedFromSource)
+    @NotNull
+    private String validateComponentNameByRegex(String componentName, String 
regex)
     {
-        String pattern = isQuotedFromSource
-                         ? 
validationConfiguration.allowedPatternForQuotedName()
-                         : validationConfiguration.allowedPatternForName();
-
-        if (!unquotedInput.matches(pattern))
-            throw new HttpException(HttpResponseStatus.BAD_REQUEST.code(),
-                                    "Invalid characters in " + exceptionHint + 
": " + maybeQuoted);
+        Objects.requireNonNull(componentName, "componentName must not be 
null");
+        if (!componentName.matches(regex))
+            throw new CassandraInputException("Invalid component name: " + 
componentName);
+        return componentName;
     }
 
     /**
-     * Validates that the unique table identifier is a valid hexadecimal
-     *
-     * @param tableId the table identifier to validate
+     * {@inheritDoc}
      */
+    @Override
     public void validateTableId(String tableId)
     {
         Objects.requireNonNull(tableId, "tableId must not be null");
@@ -197,31 +149,45 @@ public class CassandraInputValidator
         {
             char c = tableId.charAt(i);
             if (!isHex(c))
-                throw new HttpException(HttpResponseStatus.BAD_REQUEST.code(),
-                                        "Invalid characters in table id: " + 
tableId);
+                throw new CassandraInputException("Invalid characters in table 
id: " + tableId);
         }
     }
 
     /**
-     * @param c the character to test
-     * @return {@code true} if the input {@code c} is valid hexadecimal, 
{@code false} otherwise
+     * {@inheritDoc}
      */
-    protected boolean isHex(char c)
+    @Override
+    public void validateNamePattern(Name name, String exceptionHint)
     {
-        return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9') || (c >= 'A' 
&& c <= 'F');
+        validatePattern(name.name(), name.maybeQuotedName(), exceptionHint, 
name.isSourceQuoted());
     }
 
     /**
-     * Removes the surrounding quotes for the name, if the quotes are present. 
Otherwise, returns the original
-     * input.
-     * Validates that the {@code name} matches the {@code patternWordChars}
+     * Validates that the {@code unquotedInput} matches the {@code 
patternWordChars}
      *
-     * @param name               name
+     * @param unquotedInput      the unquoted input
+     * @param maybeQuoted        the original input used for the exception 
message
      * @param exceptionHint      hint to add in the exception message
-     * @throws HttpException when the {@code unquotedInput} does not match the 
pattern
+     * @param isQuotedFromSource whether the name was quoted from source
+     * @throws CassandraInputException when the {@code unquotedInput} does not 
match the pattern
      */
-    public void validateNamePattern(Name name, String exceptionHint)
+    protected void validatePattern(String unquotedInput, String maybeQuoted,
+                                   String exceptionHint, boolean 
isQuotedFromSource)
     {
-        validatePattern(name.name(), name.maybeQuotedName(), exceptionHint, 
name.isSourceQuoted());
+        String pattern = isQuotedFromSource
+                         ? 
validationConfiguration.allowedPatternForQuotedName()
+                         : validationConfiguration.allowedPatternForName();
+
+        if (!unquotedInput.matches(pattern))
+            throw new CassandraInputException("Invalid characters in " + 
exceptionHint + ": " + maybeQuoted);
+    }
+
+    /**
+     * @param c the character to test
+     * @return {@code true} if the input {@code c} is valid hexadecimal, 
{@code false} otherwise
+     */
+    protected boolean isHex(char c)
+    {
+        return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9') || (c >= 'A' 
&& c <= 'F');
     }
 }
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
 
b/server/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
index 45e763b9..db83cedd 100644
--- 
a/server/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
@@ -23,6 +23,7 @@ import java.net.InetSocketAddress;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
 
@@ -98,13 +99,19 @@ class SidecarConfigurationTest
         CassandraInputValidationConfiguration validationConfiguration =
         configuration.cassandraInputValidationConfiguration();
 
+        
assertThat(validationConfiguration.validatorConfiguration()).isNotNull();
+        
assertThat(validationConfiguration.validatorConfiguration().className())
+        
.isEqualTo("org.apache.cassandra.sidecar.utils.FastCassandraInputValidator");
+        
assertThat(validationConfiguration.validatorConfiguration().namedParameters())
+        .containsExactlyInAnyOrderEntriesOf(Map.of("valid_terminations", 
".abc,.def",
+                                                   
"valid_restricted_terminations", ".xml"));
         assertThat(validationConfiguration.forbiddenKeyspaces()).contains("a", 
"b", "c");
         
assertThat(validationConfiguration.allowedPatternForName()).isEqualTo("[a-z]+");
         
assertThat(validationConfiguration.allowedPatternForQuotedName()).isEqualTo("[A-Z]+");
         assertThat(validationConfiguration.allowedPatternForComponentName())
-        .isEqualTo("(.db|.cql|.json|.crc32|TOC.txt)");
+        .isEqualTo("(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)");
         
assertThat(validationConfiguration.allowedPatternForRestrictedComponentName())
-        .isEqualTo("(.db|TOC.txt)");
+        .isEqualTo("(\\.db|TOC\\.txt)");
     }
 
     @Test
@@ -492,7 +499,7 @@ class SidecarConfigurationTest
     void testDnsResolverResolveToIp() throws Exception
     {
         String yaml = "sidecar:\n" +
-                "  dns_resolver: resolve_to_ip";
+                      "  dns_resolver: resolve_to_ip";
         SidecarConfiguration config = 
SidecarConfigurationImpl.fromYamlString(yaml);
         ServiceConfiguration serviceConfiguration = 
config.serviceConfiguration();
         assertThat(serviceConfiguration).isNotNull();
@@ -740,8 +747,8 @@ class SidecarConfigurationTest
         
assertThat(config.allowedPatternForName()).isEqualTo("[a-zA-Z][a-zA-Z0-9_]{0,47}");
         
assertThat(config.allowedPatternForQuotedName()).isEqualTo("[a-zA-Z_0-9]{1,48}");
         assertThat(config.allowedPatternForComponentName())
-        .isEqualTo("[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)");
-        
assertThat(config.allowedPatternForRestrictedComponentName()).isEqualTo("[a-zA-Z0-9_-]+(.db|TOC.txt)");
+        .isEqualTo("[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)");
+        
assertThat(config.allowedPatternForRestrictedComponentName()).isEqualTo("[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)");
     }
 
     void 
validateVertxFilesystemOptionsClasspathResolvingDisabled(FileSystemOptionsConfiguration
 config)
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/utils/CassandraInputValidatorTest.java
 
b/server/src/test/java/org/apache/cassandra/sidecar/utils/CassandraInputValidatorTest.java
index 4a98dabb..400c77d1 100644
--- 
a/server/src/test/java/org/apache/cassandra/sidecar/utils/CassandraInputValidatorTest.java
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/utils/CassandraInputValidatorTest.java
@@ -24,48 +24,50 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
 
-import io.netty.handler.codec.http.HttpResponseStatus;
-import io.vertx.ext.web.handler.HttpException;
+import org.apache.cassandra.sidecar.exceptions.CassandraInputException;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatNullPointerException;
 
 /**
  * Test validation methods.
  */
-public class CassandraInputValidatorTest
+abstract class CassandraInputValidatorTest
 {
     CassandraInputValidator instance;
 
     @BeforeEach
     void setup()
     {
-        instance = new CassandraInputValidator();
+        instance = initializeInstanceForTest();
     }
 
+    protected abstract CassandraInputValidator initializeInstanceForTest();
+
     @ParameterizedTest(name = "[{0}]")
     @ValueSource(strings = { "test_table_name", "\"test_table_name\"", 
"testTableName", "\"testTableName\"", "a_",
                              "\"cycling\"", "\"Helmets\"", "\"mIxEd_cAsE\"", 
"a8", "a", "\"8a\"",
                              "\"_must_begin_with_alphabetic_unless_quoted_p\"" 
})
-    public void testValidTableNameValidation(String tableName)
+    void testValidTableNameValidation(String tableName)
     {
         instance.validateTableName(tableName);
     }
 
     @ParameterizedTest(name = "[{0}]")
-    @ValueSource(strings = { "", "test table", "_must_begin_with_alphabetic", 
"dash-is-not-allowed", "\"\"", "\"",
+    @ValueSource(strings = { "test table", "_must_begin_with_alphabetic", 
"dash-is-not-allowed", "\"",
                              "\"inv@lid_chars\"", "test:table_name", 
"test-table$name", "8a", "testTable/Name" })
-    public void failsWithInvalidTableName(String tableName)
+    void failsWithInvalidTableName(String tableName)
     {
-        HttpException httpEx = Assertions.assertThrows(HttpException.class,
-                                                       () -> 
instance.validateTableName(tableName));
-        
assertThat(httpEx.getStatusCode()).isEqualTo(HttpResponseStatus.BAD_REQUEST.code());
-        assertThat(httpEx.getPayload()).isEqualTo("Invalid characters in table 
name: " + tableName);
+        assertThatExceptionOfType(CassandraInputException.class)
+        .isThrownBy(() -> instance.validateTableName(tableName))
+        .withMessage("Invalid characters in table name: " + tableName);
     }
 
     @ParameterizedTest(name = "[{0}]")
     @ValueSource(strings = { "SystemViews", "system_views_test", 
"\"keyspace\"", "\"cycling\"", "\"Cycling\"",
-                             "\"mIxEd_cAsE\"", "a8", "a", "a_", "\"_a\"" })
-    public void testValidKeyspaceValidation(String keyspace)
+                             "\"mIxEd_cAsE\"", "a8", "a", "a_", "\"_a\"", 
"keyspace_name_can_only_have_48_characters_345678" })
+    void testValidKeyspaceValidation(String keyspace)
     {
         instance.validateKeyspaceName(keyspace);
     }
@@ -78,70 +80,60 @@ public class CassandraInputValidatorTest
                              "system_auth",
                              "system_views",
                              "system_virtual_schema" })
-    public void failsWithForbiddenKeyspace(String keyspace)
+    void failsWithForbiddenKeyspace(String keyspace)
     {
-        HttpException httpEx = Assertions.assertThrows(HttpException.class,
-                                                       () -> 
instance.validateKeyspaceName(keyspace));
-        
assertThat(httpEx.getStatusCode()).isEqualTo(HttpResponseStatus.FORBIDDEN.code());
-        assertThat(httpEx.getPayload()).isEqualTo("Forbidden keyspace: " + 
keyspace);
+        assertThatExceptionOfType(CassandraInputException.class).isThrownBy(() 
-> instance.validateKeyspaceName(keyspace))
+                                                                
.withMessage("Forbidden keyspace: " + keyspace);
     }
 
     @ParameterizedTest(name = "[{0}]")
-    @ValueSource(strings = { "", "test keyspace", "_cycling", 
"dash-is-not-allowed", "\"\"", "\"",
-                             "\"inv@lid_chars\"", "8a" })
-    public void failsWithInvalidKeyspaceName(String keyspace)
+    @ValueSource(strings = { "test keyspace", "_cycling", 
"dash-is-not-allowed", "\"", "\"inv@lid_chars\"", "8a" })
+    void failsWithInvalidKeyspaceName(String keyspace)
     {
-        HttpException httpEx = Assertions.assertThrows(HttpException.class,
-                                                       () -> 
instance.validateKeyspaceName(keyspace));
-        
assertThat(httpEx.getStatusCode()).isEqualTo(HttpResponseStatus.BAD_REQUEST.code());
-        assertThat(httpEx.getPayload()).isEqualTo("Invalid characters in 
keyspace: " + keyspace);
+        assertThatExceptionOfType(CassandraInputException.class)
+        .isThrownBy(() -> instance.validateKeyspaceName(keyspace))
+        .withMessage("Invalid characters in keyspace: " + keyspace);
     }
 
-    @Test
-    public void testValidateFileName_validFileNames_expectNoException()
+    @ParameterizedTest(name = "[{0}]")
+    @ValueSource(strings = { "test-file-name.db", "test_file_name.json", 
"testFileName.cql", "t_TOC.txt", "crcfile.crc32" })
+    void testValidateFileName_validFileNames_expectNoException(String 
componentName)
     {
-        instance.validateComponentName("test-file-name.db");
-        instance.validateComponentName("test_file_name.json");
-        instance.validateComponentName("testFileName.cql");
-        instance.validateComponentName("t_TOC.txt");
-        instance.validateComponentName("crcfile.crc32");
+        instance.validateComponentName(componentName);
     }
 
     private void testCommon_testInvalidFileName(String testFileName)
     {
-        HttpException httpEx = Assertions.assertThrows(HttpException.class,
-                                                       () -> 
instance.validateComponentName(testFileName));
-        
assertThat(httpEx.getStatusCode()).isEqualTo(HttpResponseStatus.BAD_REQUEST.code());
-        assertThat(httpEx.getPayload()).isEqualTo("Invalid component name: " + 
testFileName);
+        assertThatExceptionOfType(CassandraInputException.class).isThrownBy(() 
-> instance.validateComponentName(testFileName))
+                                                                
.withMessage("Invalid component name: " + testFileName);
     }
 
     @Test
-    public void testValidateFileName_withoutExtension_expectException()
+    void testValidateFileName_withoutExtension_expectException()
     {
         testCommon_testInvalidFileName("test-file-name");
     }
 
     @Test
-    public void testValidateFileName_incorrectExtension_expectException()
+    void testValidateFileName_incorrectExtension_expectException()
     {
         testCommon_testInvalidFileName("test-file-name.db1");
     }
 
     @Test
-    public void testValidateFileName_incorrectCrcExtension_expectException()
+    void testValidateFileName_incorrectCrcExtension_expectException()
     {
         testCommon_testInvalidFileName("crcfile.crc64");
     }
 
     @Test
-    public void testValidateFileName_withoutFileName_expectException()
+    void testValidateFileName_withoutFileName_expectException()
     {
         testCommon_testInvalidFileName("TOC.txt");
     }
 
-
     @Test
-    public void testValidateSnapshotName_validSnapshotNames_expectNoException()
+    void testValidateSnapshotName_validSnapshotNames_expectNoException()
     {
         instance.validateSnapshotName("valid-snapshot-name");
         instance.validateSnapshotName("valid\\snapshot\\name");
@@ -151,23 +143,19 @@ public class CassandraInputValidatorTest
     }
 
     @Test
-    public void 
testValidateSnapshotName_snapshotNameWithSlash_expectException()
+    void testValidateSnapshotName_snapshotNameWithSlash_expectException()
     {
         String testSnapName = "valid" + '/' + "snapshotname";
-        HttpException httpEx = Assertions.assertThrows(HttpException.class,
-                                                       () -> 
instance.validateSnapshotName(testSnapName));
-        
assertThat(httpEx.getStatusCode()).isEqualTo(HttpResponseStatus.BAD_REQUEST.code());
-        assertThat(httpEx.getPayload()).isEqualTo("Invalid characters in 
snapshot name: " + testSnapName);
+        assertThatExceptionOfType(CassandraInputException.class).isThrownBy(() 
-> instance.validateSnapshotName(testSnapName))
+                                                                
.withMessage("Invalid characters in snapshot name: " + testSnapName);
     }
 
     @Test
-    public void 
testValidateSnapshotName_snapshotNameWithNullChar_expectException()
+    void testValidateSnapshotName_snapshotNameWithNullChar_expectException()
     {
         String testSnapName = "valid" + '\0' + "snapshotname";
-        HttpException httpEx = Assertions.assertThrows(HttpException.class,
-                                                       () -> 
instance.validateSnapshotName(testSnapName));
-        
assertThat(httpEx.getStatusCode()).isEqualTo(HttpResponseStatus.BAD_REQUEST.code());
-        assertThat(httpEx.getPayload()).isEqualTo("Invalid characters in 
snapshot name: " + testSnapName);
+        assertThatExceptionOfType(CassandraInputException.class).isThrownBy(() 
-> instance.validateSnapshotName(testSnapName))
+                                                                
.withMessage("Invalid characters in snapshot name: " + testSnapName);
     }
 
     @Test
@@ -196,9 +184,63 @@ public class CassandraInputValidatorTest
     @ValueSource(strings = { "g", "--", "abc-124", "z", "x", "xax" })
     void testInvalidTableId(String tableId)
     {
-        HttpException httpEx = Assertions.assertThrows(HttpException.class,
-                                                       () -> 
instance.validateTableId(tableId));
-        
assertThat(httpEx.getStatusCode()).isEqualTo(HttpResponseStatus.BAD_REQUEST.code());
-        assertThat(httpEx.getPayload()).isEqualTo("Invalid characters in table 
id: " + tableId);
+        assertThatExceptionOfType(CassandraInputException.class).isThrownBy(() 
-> instance.validateTableId(tableId))
+                                                                
.withMessage("Invalid characters in table id: " + tableId);
+    }
+
+    @Test
+    void failsOnNullComponentName()
+    {
+        assertThatNullPointerException().isThrownBy(() -> 
instance.validateComponentName(null))
+                                        .withMessage("componentName must not 
be null");
+    }
+
+    @Test
+    void failsOnNullRestrictedComponentName()
+    {
+        assertThatNullPointerException().isThrownBy(() -> 
instance.validateRestrictedComponentName(null))
+                                        .withMessage("componentName must not 
be null");
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "nb-35460-big-Filter.db", "nb-35460-big-Index.db",
+                             "nb-35460-big-Summary.db", 
"nb-35460-big-Digest.crc32",
+                             "nb-35460-big-Data.db", 
"nb-35460-big-CompressionInfo.db",
+                             "nb-35460-big-TOC.txt", 
"nb-35460-big-Statistics.db" })
+    void testValidComponentNameValidation(String componentName)
+    {
+        
assertThat(instance.validateComponentName(componentName)).isEqualTo(componentName);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "ks_name-table_name-nb-35460-big-Filter.db", 
"ks_name-table_name-nb-35460-big-Index.db",
+                             "ks_name-table_name-nb-35460-big-Summary.db", 
"ks_name-table_name-nb-35460-big-Data.db",
+                             
"ks_name-table_name-nb-35460-big-CompressionInfo.db", 
"ks_name-table_name-nb-35460-big-TOC.txt",
+                             "ks_name-table_name-nb-35460-big-Statistics.db" })
+    void testValidRestrictedComponentNameValidation(String componentName)
+    {
+        
assertThat(instance.validateRestrictedComponentName(componentName)).isEqualTo(componentName);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "@nb-35460-big-Filter.db", 
"nb-35460-big-Index.not-valid-ending",
+                             "nb-35460-big-duplicate-db.db.db", 
"nb*35460-big-Digest.crc32",
+                             "nb-35460-big-Data-no-dot-db" })
+    void failsOnInvalidComponentName(String componentName)
+    {
+        assertThatExceptionOfType(CassandraInputException.class)
+        .isThrownBy(() -> instance.validateComponentName(componentName))
+        .withMessage("Invalid component name: " + componentName);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "@nb-35460-big-Filter.db", 
"nb-35460-big-Index.not-valid-ending",
+                             "nb-35460-big-Summary.db.db", 
"nb-35460-big-Digest.crc32",
+                             "nb*35460-big-Data.db", 
"nb-35460-big-CompressionInfo-no-dot-db" })
+    void failsOnInvalidRestrictedComponentName(String componentName)
+    {
+        assertThatExceptionOfType(CassandraInputException.class)
+        .isThrownBy(() -> 
instance.validateRestrictedComponentName(componentName))
+        .withMessage("Invalid component name: " + componentName);
     }
 }
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/utils/FastCassandraInputValidatorTest.java
 
b/server/src/test/java/org/apache/cassandra/sidecar/utils/FastCassandraInputValidatorTest.java
new file mode 100644
index 00000000..5767bdd9
--- /dev/null
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/utils/FastCassandraInputValidatorTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.utils;
+
+import java.util.List;
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import 
org.apache.cassandra.sidecar.config.CassandraInputValidationConfiguration;
+import org.apache.cassandra.sidecar.config.ParameterizedClassConfiguration;
+import 
org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl;
+import 
org.apache.cassandra.sidecar.config.yaml.ParameterizedClassConfigurationImpl;
+import org.apache.cassandra.sidecar.exceptions.CassandraInputException;
+
+import static 
org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl.DEFAULT_ALLOWED_CHARS_FOR_COMPONENT_NAME;
+import static 
org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl.DEFAULT_ALLOWED_CHARS_FOR_NAME;
+import static 
org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl.DEFAULT_ALLOWED_CHARS_FOR_QUOTED_NAME;
+import static 
org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl.DEFAULT_ALLOWED_CHARS_FOR_RESTRICTED_COMPONENT_NAME;
+import static 
org.apache.cassandra.sidecar.config.yaml.CassandraInputValidationConfigurationImpl.DEFAULT_FORBIDDEN_KEYSPACES;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static 
org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+
+/**
+ * Unit tests for {@link FastCassandraInputValidator}
+ */
+class FastCassandraInputValidatorTest extends CassandraInputValidatorTest
+{
+    @Override
+    protected CassandraInputValidator initializeInstanceForTest()
+    {
+        return new FastCassandraInputValidator();
+    }
+
+    @Test
+    void testParsingOfConfigurationValues()
+    {
+        Map<String, String> validTerminationConfig = 
Map.of("valid_terminations", ".abc,.def",
+                                                            
"valid_restricted_terminations", ".xml");
+        ParameterizedClassConfiguration validatorConfiguration = new 
ParameterizedClassConfigurationImpl("ignored", validTerminationConfig);
+        CassandraInputValidationConfiguration config = new 
CassandraInputValidationConfigurationImpl(validatorConfiguration,
+                                                                               
                      DEFAULT_FORBIDDEN_KEYSPACES,
+                                                                               
                      DEFAULT_ALLOWED_CHARS_FOR_NAME,
+                                                                               
                      DEFAULT_ALLOWED_CHARS_FOR_QUOTED_NAME,
+                                                                               
                      DEFAULT_ALLOWED_CHARS_FOR_COMPONENT_NAME,
+                                                                               
                      DEFAULT_ALLOWED_CHARS_FOR_RESTRICTED_COMPONENT_NAME);
+        FastCassandraInputValidator validator = new 
FastCassandraInputValidator(config);
+        assertThat(validator.validTerminations).isEqualTo(List.of(".abc", 
".def"));
+        
assertThat(validator.validRestrictedTerminations).isEqualTo(List.of(".xml"));
+    }
+
+    @ParameterizedTest(name = "[{0}]")
+    @ValueSource(strings = { "", "\"\"",
+                             
"very_long_table_name_that_exceeds_two_hundred_and_twenty_two_characters_to_test_upper_"
 +
+                             
"limit_of_a_table_also_known_as_column_family_the_upper_limit_is_due_to_limitations_by_"
 +
+                             
"the_name_of_file_systems_and_it_also_includes_tid_1" })
+    void failsWithInvalidLengthForTableName(String tableName)
+    {
+        assertThatExceptionOfType(CassandraInputException.class)
+        .isThrownBy(() -> instance.validateTableName(tableName))
+        .withMessageMatching("Invalid length \\d+ for table name: " + 
tableName);
+    }
+
+    @ParameterizedTest(name = "[{0}]")
+    @ValueSource(strings = { "", "\"\"", 
"keyspace_name_can_only_have_48_characters_or_it_will_fail" })
+    void failsWithInvalidLengthForKeyspaceName(String keyspace)
+    {
+        assertThatExceptionOfType(CassandraInputException.class)
+        .isThrownBy(() -> instance.validateKeyspaceName(keyspace))
+        .withMessageMatching("Invalid length \\d+ for keyspace: " + keyspace);
+    }
+
+    @Test
+    void failsOnEmptyComponentName()
+    {
+        assertThatIllegalArgumentException().isThrownBy(() -> 
instance.validateComponentName(""))
+                                            .withMessage("componentName cannot 
be empty");
+    }
+
+    @Test
+    void failsOnEmptyRestrictedComponentName()
+    {
+        assertThatIllegalArgumentException().isThrownBy(() -> 
instance.validateRestrictedComponentName(""))
+                                            .withMessage("componentName cannot 
be empty");
+    }
+}
diff --git 
a/server/src/test/java/org/apache/cassandra/sidecar/utils/RegexBasedCassandraInputValidatorTest.java
 
b/server/src/test/java/org/apache/cassandra/sidecar/utils/RegexBasedCassandraInputValidatorTest.java
new file mode 100644
index 00000000..f28439f9
--- /dev/null
+++ 
b/server/src/test/java/org/apache/cassandra/sidecar/utils/RegexBasedCassandraInputValidatorTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.sidecar.utils;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import org.apache.cassandra.sidecar.exceptions.CassandraInputException;
+
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static 
org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+
+/**
+ * Unit tests for {@link RegexBasedCassandraInputValidator}
+ */
+class RegexBasedCassandraInputValidatorTest extends CassandraInputValidatorTest
+{
+    @Override
+    protected CassandraInputValidator initializeInstanceForTest()
+    {
+        return new RegexBasedCassandraInputValidator();
+    }
+
+    @ParameterizedTest(name = "[{0}]")
+    @ValueSource(strings = { "", "\"\"",
+                             
"very_long_table_name_that_exceeds_two_hundred_and_twenty_two_characters_to_test_upper_limit"
 +
+                             
"_of_a_table_also_known_as_column_family_the_upper_limit_is_due_to_limitations_by_the_name"
 +
+                             "_of_file_systems_and_it_also_includes_tid_1" })
+    void failsWithInvalidLengthForTableName(String tableName)
+    {
+        assertThatExceptionOfType(CassandraInputException.class)
+        .isThrownBy(() -> instance.validateTableName(tableName))
+        .withMessage("Invalid characters in table name: " + tableName);
+    }
+
+    @ParameterizedTest(name = "[{0}]")
+    @ValueSource(strings = { "", "\"\"", 
"keyspace_name_can_only_have_48_characters_or_it_will_fail" })
+    void failsWithInvalidLengthForKeyspaceName(String keyspace)
+    {
+        assertThatExceptionOfType(CassandraInputException.class)
+        .isThrownBy(() -> instance.validateKeyspaceName(keyspace))
+        .withMessageMatching("Invalid characters in keyspace: " + keyspace);
+    }
+
+    @Test
+    void failsOnEmptyComponentName()
+    {
+        assertThatIllegalArgumentException().isThrownBy(() -> 
instance.validateComponentName(""))
+                                            .withMessage("Invalid component 
name: ");
+    }
+
+    @Test
+    void failsOnEmptyRestrictedComponentName()
+    {
+        assertThatIllegalArgumentException().isThrownBy(() -> 
instance.validateRestrictedComponentName(""))
+                                            .withMessage("Invalid component 
name: ");
+    }
+}
diff --git a/server/src/test/resources/config/sidecar_file_permissions.yaml 
b/server/src/test/resources/config/sidecar_file_permissions.yaml
index f951e8ac..04ee506c 100644
--- a/server/src/test/resources/config/sidecar_file_permissions.yaml
+++ b/server/src/test/resources/config/sidecar_file_permissions.yaml
@@ -115,5 +115,5 @@ cassandra_input_validation:
     - system_virtual_schema
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z0-9_-]+"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git 
a/server/src/test/resources/config/sidecar_invalid_accesscontrol_config.yaml 
b/server/src/test/resources/config/sidecar_invalid_accesscontrol_config.yaml
index d9633d1e..de3dcb9d 100644
--- a/server/src/test/resources/config/sidecar_invalid_accesscontrol_config.yaml
+++ b/server/src/test/resources/config/sidecar_invalid_accesscontrol_config.yaml
@@ -113,5 +113,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git a/server/src/test/resources/config/sidecar_invalid_client_auth.yaml 
b/server/src/test/resources/config/sidecar_invalid_client_auth.yaml
index 067c5ff1..9c10288f 100644
--- a/server/src/test/resources/config/sidecar_invalid_client_auth.yaml
+++ b/server/src/test/resources/config/sidecar_invalid_client_auth.yaml
@@ -128,5 +128,5 @@ cassandra_input_validation:
     - system_virtual_schema
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z0-9_-]+"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git 
a/server/src/test/resources/config/sidecar_invalid_file_permissions.yaml 
b/server/src/test/resources/config/sidecar_invalid_file_permissions.yaml
index 4c7a57ea..604fd57f 100644
--- a/server/src/test/resources/config/sidecar_invalid_file_permissions.yaml
+++ b/server/src/test/resources/config/sidecar_invalid_file_permissions.yaml
@@ -115,5 +115,5 @@ cassandra_input_validation:
     - system_virtual_schema
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z0-9_-]+"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git a/server/src/test/resources/config/sidecar_live_migration.yaml 
b/server/src/test/resources/config/sidecar_live_migration.yaml
index 5ce70fa8..51cacfdc 100644
--- a/server/src/test/resources/config/sidecar_live_migration.yaml
+++ b/server/src/test/resources/config/sidecar_live_migration.yaml
@@ -201,8 +201,8 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
 
 live_migration:
   files_to_exclude:
diff --git a/server/src/test/resources/config/sidecar_metrics.yaml 
b/server/src/test/resources/config/sidecar_metrics.yaml
index a216e8ba..b215d324 100644
--- a/server/src/test/resources/config/sidecar_metrics.yaml
+++ b/server/src/test/resources/config/sidecar_metrics.yaml
@@ -87,5 +87,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git 
a/server/src/test/resources/config/sidecar_metrics_empty_filters.yaml 
b/server/src/test/resources/config/sidecar_metrics_empty_filters.yaml
index 67a1c205..54c3f648 100644
--- a/server/src/test/resources/config/sidecar_metrics_empty_filters.yaml
+++ b/server/src/test/resources/config/sidecar_metrics_empty_filters.yaml
@@ -79,5 +79,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git a/server/src/test/resources/config/sidecar_missing_jmx.yaml 
b/server/src/test/resources/config/sidecar_missing_jmx.yaml
index 0068126e..6000ab89 100644
--- a/server/src/test/resources/config/sidecar_missing_jmx.yaml
+++ b/server/src/test/resources/config/sidecar_missing_jmx.yaml
@@ -129,5 +129,5 @@ cassandra_input_validation:
     - system_virtual_schema
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z0-9_-]+"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git a/server/src/test/resources/config/sidecar_multiple_instances.yaml 
b/server/src/test/resources/config/sidecar_multiple_instances.yaml
index 88b17b8e..b0480fc2 100644
--- a/server/src/test/resources/config/sidecar_multiple_instances.yaml
+++ b/server/src/test/resources/config/sidecar_multiple_instances.yaml
@@ -201,5 +201,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git a/server/src/test/resources/config/sidecar_no_local_instances.yaml 
b/server/src/test/resources/config/sidecar_no_local_instances.yaml
index 10948884..c5fbcf27 100644
--- a/server/src/test/resources/config/sidecar_no_local_instances.yaml
+++ b/server/src/test/resources/config/sidecar_no_local_instances.yaml
@@ -81,5 +81,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git 
a/server/src/test/resources/config/sidecar_schema_keyspace_configuration.yaml 
b/server/src/test/resources/config/sidecar_schema_keyspace_configuration.yaml
index 60c96e96..518343ca 100644
--- 
a/server/src/test/resources/config/sidecar_schema_keyspace_configuration.yaml
+++ 
b/server/src/test/resources/config/sidecar_schema_keyspace_configuration.yaml
@@ -98,5 +98,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git a/server/src/test/resources/config/sidecar_single_instance.yaml 
b/server/src/test/resources/config/sidecar_single_instance.yaml
index 84b0a009..8ca49aaa 100644
--- a/server/src/test/resources/config/sidecar_single_instance.yaml
+++ b/server/src/test/resources/config/sidecar_single_instance.yaml
@@ -116,5 +116,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git 
a/server/src/test/resources/config/sidecar_single_instance_non_zero_port.yaml 
b/server/src/test/resources/config/sidecar_single_instance_non_zero_port.yaml
index 3e5438c7..413274fe 100644
--- 
a/server/src/test/resources/config/sidecar_single_instance_non_zero_port.yaml
+++ 
b/server/src/test/resources/config/sidecar_single_instance_non_zero_port.yaml
@@ -102,5 +102,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git a/server/src/test/resources/config/sidecar_ssl.yaml 
b/server/src/test/resources/config/sidecar_ssl.yaml
index f9926f02..dd5e8fd9 100644
--- a/server/src/test/resources/config/sidecar_ssl.yaml
+++ b/server/src/test/resources/config/sidecar_ssl.yaml
@@ -161,5 +161,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git 
a/server/src/test/resources/config/sidecar_unrecognized_authenticator.yaml 
b/server/src/test/resources/config/sidecar_unrecognized_authenticator.yaml
index da8a862a..16444a37 100644
--- a/server/src/test/resources/config/sidecar_unrecognized_authenticator.yaml
+++ b/server/src/test/resources/config/sidecar_unrecognized_authenticator.yaml
@@ -115,5 +115,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git 
a/server/src/test/resources/config/sidecar_unrecognized_authorizer.yaml 
b/server/src/test/resources/config/sidecar_unrecognized_authorizer.yaml
index 7a2655f7..c11f6ede 100644
--- a/server/src/test/resources/config/sidecar_unrecognized_authorizer.yaml
+++ b/server/src/test/resources/config/sidecar_unrecognized_authorizer.yaml
@@ -119,5 +119,5 @@ cassandra_input_validation:
     - system_virtual_schema
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git 
a/server/src/test/resources/config/sidecar_validation_configuration.yaml 
b/server/src/test/resources/config/sidecar_validation_configuration.yaml
index 717cff7a..ed556468 100644
--- a/server/src/test/resources/config/sidecar_validation_configuration.yaml
+++ b/server/src/test/resources/config/sidecar_validation_configuration.yaml
@@ -25,11 +25,16 @@ sidecar:
     execute_interval: 50ms
 
 cassandra_input_validation:
+  validator:
+  - class_name: org.apache.cassandra.sidecar.utils.FastCassandraInputValidator
+    parameters:
+      valid_terminations: ".abc,.def"
+      valid_restricted_terminations: ".xml"
   forbidden_keyspaces:
     - a
     - b
     - c
   allowed_chars_for_directory: "[a-z]+"
   allowed_chars_for_quoted_name: "[A-Z]+"
-  allowed_chars_for_component_name: "(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "(.db|TOC.txt)"
+  allowed_chars_for_component_name: "(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: "(\\.db|TOC\\.txt)"
diff --git 
a/server/src/test/resources/config/sidecar_vertx_filesystem_options.yaml 
b/server/src/test/resources/config/sidecar_vertx_filesystem_options.yaml
index 32dc3981..c00bc9c4 100644
--- a/server/src/test/resources/config/sidecar_vertx_filesystem_options.yaml
+++ b/server/src/test/resources/config/sidecar_vertx_filesystem_options.yaml
@@ -108,5 +108,5 @@ cassandra_input_validation:
     - sidecar_internal
   allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
   allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
-  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
-  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(\\.db|\\.cql|\\.json|\\.crc32|TOC\\.txt)"
+  allowed_chars_for_restricted_component_name: 
"[a-zA-Z0-9_-]+(\\.db|TOC\\.txt)"
diff --git 
a/server/src/testFixtures/java/org/apache/cassandra/sidecar/snapshots/AbstractSnapshotPathBuilderTest.java
 
b/server/src/testFixtures/java/org/apache/cassandra/sidecar/snapshots/AbstractSnapshotPathBuilderTest.java
index ec343c81..dc0473ee 100644
--- 
a/server/src/testFixtures/java/org/apache/cassandra/sidecar/snapshots/AbstractSnapshotPathBuilderTest.java
+++ 
b/server/src/testFixtures/java/org/apache/cassandra/sidecar/snapshots/AbstractSnapshotPathBuilderTest.java
@@ -45,6 +45,7 @@ import org.apache.cassandra.sidecar.concurrent.ExecutorPools;
 import org.apache.cassandra.sidecar.config.ServiceConfiguration;
 import org.apache.cassandra.sidecar.config.yaml.ServiceConfigurationImpl;
 import org.apache.cassandra.sidecar.utils.CassandraInputValidator;
+import org.apache.cassandra.sidecar.utils.FastCassandraInputValidator;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -69,7 +70,7 @@ public abstract class AbstractSnapshotPathBuilderTest
     @BeforeEach
     protected void setup() throws IOException
     {
-        CassandraInputValidator validator = new CassandraInputValidator();
+        CassandraInputValidator validator = new FastCassandraInputValidator();
 
         InstancesMetadata mockInstancesMetadata = 
mock(InstancesMetadata.class);
         InstanceMetadata mockInstanceMeta = mock(InstanceMetadata.class);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to