This is an automated email from the ASF dual-hosted git repository.
domgarguilo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo-access.git
The following commit(s) were added to refs/heads/main by this push:
new 261b5c3 Miscellaneous Improvements (#27)
261b5c3 is described below
commit 261b5c303df3bae0d311689e14e1e029ae43d849
Author: Dom G <[email protected]>
AuthorDate: Thu Oct 26 15:17:41 2023 -0400
Miscellaneous Improvements (#27)
* Misc cleanup
* Remove mentions of mutations and visibility
* Add byte constant class and helper methods
---------
Co-authored-by: Dave Marion <[email protected]>
Co-authored-by: Keith Turner <[email protected]>
---
README.md | 2 +-
.../apache/accumulo/access/AccessEvaluator.java | 10 ++--
.../accumulo/access/AccessEvaluatorImpl.java | 67 +++++++++++-----------
.../apache/accumulo/access/AccessExpression.java | 18 +++---
.../accumulo/access/AccessExpressionImpl.java | 21 +++----
.../java/org/apache/accumulo/access/AeNode.java | 7 ++-
.../org/apache/accumulo/access/Authorizations.java | 1 +
.../java/org/apache/accumulo/access/ByteUtils.java | 58 +++++++++++++++++++
.../org/apache/accumulo/access/BytesWrapper.java | 14 ++++-
.../java/org/apache/accumulo/access/Parser.java | 14 +++--
.../java/org/apache/accumulo/access/Tokenizer.java | 49 +++++++---------
11 files changed, 165 insertions(+), 96 deletions(-)
diff --git a/README.md b/README.md
index e43991c..a754d7f 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ Apache Accumulo [ColumnVisibility][1] and
[VisibilityEvaluator][2] classes.
This functionality is provided in a standalone java library that has no
dependencies (for example no Hadoop, Zookeeper, Thrift, etc dependencies).
-For a conceptual overview of what an access expression is see the
+For a conceptual overview of what an access expression is, see the
[specification](SPECIFICATION.md) document. See the [getting started
guide](contrib/getting-started/README.md) for an example of how to use
this java library.
diff --git a/src/main/java/org/apache/accumulo/access/AccessEvaluator.java
b/src/main/java/org/apache/accumulo/access/AccessEvaluator.java
index ecf1f3e..c0123ed 100644
--- a/src/main/java/org/apache/accumulo/access/AccessEvaluator.java
+++ b/src/main/java/org/apache/accumulo/access/AccessEvaluator.java
@@ -86,7 +86,7 @@ public interface AccessEvaluator {
interface AuthorizationsBuilder {
- FinalBuilder authorizations(Authorizations authorizations);
+ EvaluatorBuilder authorizations(Authorizations authorizations);
/**
* Allows providing multiple sets of authorizations. Each expression will
be evaluated
@@ -139,20 +139,20 @@ public interface AccessEvaluator {
*
*
*/
- FinalBuilder authorizations(Collection<Authorizations> authorizations);
+ EvaluatorBuilder authorizations(Collection<Authorizations> authorizations);
/**
* Allows specifying a single set of authorizations.
*/
- FinalBuilder authorizations(String... authorizations);
+ EvaluatorBuilder authorizations(String... authorizations);
/**
* Allows specifying an authorizer that is analogous to a single set of
authorization.
*/
- FinalBuilder authorizations(Authorizer authorizer);
+ EvaluatorBuilder authorizations(Authorizer authorizer);
}
- interface FinalBuilder {
+ interface EvaluatorBuilder {
AccessEvaluator build();
}
diff --git a/src/main/java/org/apache/accumulo/access/AccessEvaluatorImpl.java
b/src/main/java/org/apache/accumulo/access/AccessEvaluatorImpl.java
index c27e9da..eb25206 100644
--- a/src/main/java/org/apache/accumulo/access/AccessEvaluatorImpl.java
+++ b/src/main/java/org/apache/accumulo/access/AccessEvaluatorImpl.java
@@ -21,6 +21,10 @@ package org.apache.accumulo.access;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toSet;
import static java.util.stream.Collectors.toUnmodifiableList;
+import static org.apache.accumulo.access.ByteUtils.BACKSLASH;
+import static org.apache.accumulo.access.ByteUtils.QUOTE;
+import static org.apache.accumulo.access.ByteUtils.isQuoteOrSlash;
+import static org.apache.accumulo.access.ByteUtils.isQuoteSymbol;
import java.util.Collection;
import java.util.Collections;
@@ -43,14 +47,14 @@ class AccessEvaluatorImpl implements AccessEvaluator {
.map(auth -> AccessEvaluatorImpl.escape(auth,
false)).map(BytesWrapper::new)
.collect(toSet()))
.map(escapedAuths -> (Predicate<BytesWrapper>) escapedAuths::contains)
- .collect(Collectors.toList());
+ .collect(Collectors.toUnmodifiableList());
}
static String unescape(BytesWrapper auth) {
int escapeCharCount = 0;
for (int i = 0; i < auth.length(); i++) {
byte b = auth.byteAt(i);
- if (b == '"' || b == '\\') {
+ if (isQuoteOrSlash(b)) {
escapeCharCount++;
}
}
@@ -67,12 +71,13 @@ class AccessEvaluatorImpl implements AccessEvaluator {
if (b == '\\') {
i++;
b = auth.byteAt(i);
- if (b != '"' && b != '\\') {
+ if (!isQuoteOrSlash(b)) {
throw new IllegalArgumentException("Illegal escape sequence in
auth : " + auth);
}
- } else if (b == '"') {
+ } else if (isQuoteSymbol(b)) {
// should only see quote after a slash
- throw new IllegalArgumentException("Illegal escape sequence in auth
: " + auth);
+ throw new IllegalArgumentException(
+ "Illegal character after slash in auth String : " + auth);
}
unescapedCopy[pos++] = b;
@@ -88,31 +93,31 @@ class AccessEvaluatorImpl implements AccessEvaluator {
* Properly escapes an authorization string. The string can be quoted if
desired.
*
* @param auth authorization string, as UTF-8 encoded bytes
- * @param quote true to wrap escaped authorization in quotes
+ * @param shouldQuote true to wrap escaped authorization in quotes
* @return escaped authorization string
*/
- static byte[] escape(byte[] auth, boolean quote) {
+ static byte[] escape(byte[] auth, boolean shouldQuote) {
int escapeCount = 0;
for (byte value : auth) {
- if (value == '"' || value == '\\') {
+ if (isQuoteOrSlash(value)) {
escapeCount++;
}
}
- if (escapeCount > 0 || quote) {
- byte[] escapedAuth = new byte[auth.length + escapeCount + (quote ? 2 :
0)];
- int index = quote ? 1 : 0;
+ if (escapeCount > 0 || shouldQuote) {
+ byte[] escapedAuth = new byte[auth.length + escapeCount + (shouldQuote ?
2 : 0)];
+ int index = shouldQuote ? 1 : 0;
for (byte b : auth) {
- if (b == '"' || b == '\\') {
- escapedAuth[index++] = '\\';
+ if (isQuoteOrSlash(b)) {
+ escapedAuth[index++] = BACKSLASH;
}
escapedAuth[index++] = b;
}
- if (quote) {
- escapedAuth[0] = '"';
- escapedAuth[escapedAuth.length - 1] = '"';
+ if (shouldQuote) {
+ escapedAuth[0] = QUOTE;
+ escapedAuth[escapedAuth.length - 1] = QUOTE;
}
auth = escapedAuth;
@@ -121,25 +126,19 @@ class AccessEvaluatorImpl implements AccessEvaluator {
}
@Override
- public boolean canAccess(String expression) throws IllegalArgumentException {
-
+ public boolean canAccess(String expression) throws
IllegalAccessExpressionException {
return evaluate(new AccessExpressionImpl(expression));
-
}
@Override
- public boolean canAccess(byte[] expression) throws IllegalArgumentException {
-
+ public boolean canAccess(byte[] expression) throws
IllegalAccessExpressionException {
return evaluate(new AccessExpressionImpl(expression));
-
}
@Override
- public boolean canAccess(AccessExpression expression) throws
IllegalArgumentException {
+ public boolean canAccess(AccessExpression expression) throws
IllegalAccessExpressionException {
if (expression instanceof AccessExpressionImpl) {
-
return evaluate((AccessExpressionImpl) expression);
-
} else {
return canAccess(expression.getExpression());
}
@@ -147,12 +146,12 @@ class AccessEvaluatorImpl implements AccessEvaluator {
public boolean evaluate(AccessExpressionImpl accessExpression)
throws IllegalAccessExpressionException {
- // The VisibilityEvaluator computes a trie from the given Authorizations,
that ColumnVisibility
- // expressions can be evaluated against.
+ // The AccessEvaluator computes a trie from the given Authorizations, that
AccessExpressions can
+ // be evaluated against.
return
authorizedPredicates.stream().allMatch(accessExpression.aeNode::canAccess);
}
- private static class BuilderImpl implements AuthorizationsBuilder,
FinalBuilder {
+ private static class BuilderImpl implements AuthorizationsBuilder,
EvaluatorBuilder {
private Authorizer authorizationsChecker;
@@ -178,14 +177,14 @@ class AccessEvaluatorImpl implements AccessEvaluator {
}
@Override
- public FinalBuilder authorizations(Authorizations authorizations) {
+ public EvaluatorBuilder authorizations(Authorizations authorizations) {
setAuthorizations(authorizations.asSet().stream().map(auth ->
auth.getBytes(UTF_8))
.collect(toUnmodifiableList()));
return this;
}
@Override
- public FinalBuilder authorizations(Collection<Authorizations>
authorizationSets) {
+ public EvaluatorBuilder authorizations(Collection<Authorizations>
authorizationSets) {
setAuthorizations(authorizationSets
.stream().map(authorizations -> authorizations.asSet().stream()
.map(auth -> auth.getBytes(UTF_8)).collect(toUnmodifiableList()))
@@ -194,14 +193,14 @@ class AccessEvaluatorImpl implements AccessEvaluator {
}
@Override
- public FinalBuilder authorizations(String... authorizations) {
+ public EvaluatorBuilder authorizations(String... authorizations) {
setAuthorizations(Stream.of(authorizations).map(auth ->
auth.getBytes(UTF_8))
.collect(toUnmodifiableList()));
return this;
}
@Override
- public FinalBuilder authorizations(Authorizer authorizationChecker) {
+ public EvaluatorBuilder authorizations(Authorizer authorizationChecker) {
if (authorizationSets != null) {
throw new IllegalStateException("Cannot set checker and
authorizations");
}
@@ -212,7 +211,8 @@ class AccessEvaluatorImpl implements AccessEvaluator {
@Override
public AccessEvaluator build() {
if (authorizationSets != null ^ authorizationsChecker == null) {
- throw new IllegalStateException();
+ throw new IllegalStateException(
+ "Exactly one of authorizationSets or authorizationsChecker must be
set, not both or none.");
}
AccessEvaluator accessEvaluator;
@@ -230,4 +230,5 @@ class AccessEvaluatorImpl implements AccessEvaluator {
public static AuthorizationsBuilder builder() {
return new BuilderImpl();
}
+
}
diff --git a/src/main/java/org/apache/accumulo/access/AccessExpression.java
b/src/main/java/org/apache/accumulo/access/AccessExpression.java
index fa20807..c940e7c 100644
--- a/src/main/java/org/apache/accumulo/access/AccessExpression.java
+++ b/src/main/java/org/apache/accumulo/access/AccessExpression.java
@@ -71,14 +71,14 @@ public interface AccessExpression {
* <p>
* As an example of deduplication, the expression {@code X&Y&X} is
equivalent to {@code X&Y}
*
- * @return A normalized version of the visibility expression that removes
duplicates and orders
- * the expression in a consistent way.
+ * @return A normalized version of the access expression that removes
duplicates and orders the
+ * expression in a consistent way.
*/
String normalize();
/**
- * @return the unique authorizations that occur in the expression. For
example, for the expression
- * {@code (A&B)|(A&C)|(A&D)} this method would return {@code
[A,B,C,D]]}
+ * @return the unique set of authorizations that occur in the expression.
For example, for the
+ * expression {@code (A&B)|(A&C)|(A&D)}, this method would return
{@code [A,B,C,D]}.
*/
Authorizations getAuthorizations();
@@ -94,7 +94,7 @@ public interface AccessExpression {
}
/**
- * @return an empty VisibilityExpression.
+ * @return an empty AccessExpression.
*/
static AccessExpression of() {
return AccessExpressionImpl.EMPTY;
@@ -104,8 +104,8 @@ public interface AccessExpression {
* Authorizations occurring in an access expression can only contain the
characters listed in the
* <a href=
*
"https://github.com/apache/accumulo-access/blob/main/SPECIFICATION.md">specification</a>
unless
- * quoted. Use this method to quote authorizations that occur in an access
expression. This method
- * will only quote if it is needed.
+ * quoted (surrounded by quotation marks). Use this method to quote
authorizations that occur in
+ * an access expression. This method will only quote if it is needed.
*/
static byte[] quote(byte[] authorization) {
return AccessExpressionImpl.quote(authorization);
@@ -115,8 +115,8 @@ public interface AccessExpression {
* Authorizations occurring in an access expression can only contain the
characters listed in the
* <a href=
*
"https://github.com/apache/accumulo-access/blob/main/SPECIFICATION.md">specification</a>
unless
- * quoted. Use this method to quote authorizations that occur in an access
expression. This method
- * will only quote if it is needed.
+ * quoted (surrounded by quotation marks). Use this method to quote
authorizations that occur in
+ * an access expression. This method will only quote if it is needed.
*/
static String quote(String authorization) {
return AccessExpressionImpl.quote(authorization);
diff --git a/src/main/java/org/apache/accumulo/access/AccessExpressionImpl.java
b/src/main/java/org/apache/accumulo/access/AccessExpressionImpl.java
index 3285f5a..3f82004 100644
--- a/src/main/java/org/apache/accumulo/access/AccessExpressionImpl.java
+++ b/src/main/java/org/apache/accumulo/access/AccessExpressionImpl.java
@@ -60,10 +60,12 @@ class AccessExpressionImpl implements AccessExpression {
}
/**
- * Creates a column visibility for a Mutation.
+ * Creates an AccessExpression.
*
- * @param expression An expression of the rights needed to see this
mutation. The expression
- * syntax is defined at the class-level documentation
+ * @param expression An expression of the rights needed to see specific
data. The expression
+ * syntax is defined within the <a href=
+ *
"https://github.com/apache/accumulo-access/blob/main/SPECIFICATION.md">specification
+ * doc</a>
*/
AccessExpressionImpl(String expression) {
this(expression.getBytes(UTF_8));
@@ -71,9 +73,9 @@ class AccessExpressionImpl implements AccessExpression {
}
/**
- * Creates a column visibility for a Mutation from a string already encoded
in UTF-8 bytes.
+ * Creates an AccessExpression from a string already encoded in UTF-8 bytes.
*
- * @param expression visibility expression, encoded as UTF-8 bytes
+ * @param expression AccessExpression, encoded as UTF-8 bytes
* @see #AccessExpressionImpl(String)
*/
AccessExpressionImpl(byte[] expression) {
@@ -98,11 +100,11 @@ class AccessExpressionImpl implements AccessExpression {
}
/**
- * Compares two ColumnVisibilities for string equivalence, not as a
meaningful comparison of terms
+ * Compares two AccessExpressions for string equivalence, not as a
meaningful comparison of terms
* and conditions.
*
- * @param otherLe other column visibility
- * @return true if this visibility equals the other via string comparison
+ * @param otherLe other AccessExpression
+ * @return true if this AccessExpression equals the other via string
comparison
*/
boolean equals(AccessExpressionImpl otherLe) {
return Arrays.equals(expression, otherLe.expression);
@@ -118,8 +120,7 @@ class AccessExpressionImpl implements AccessExpression {
}
/**
- * Properly quotes terms in a column visibility expression. If no quoting is
needed, then nothing
- * is done.
+ * Properly quotes terms in an AccessExpression. If no quoting is needed,
then nothing is done.
*
* @param term term to quote, encoded as UTF-8 bytes
* @return quoted term (unquoted if unnecessary), encoded as UTF-8 bytes
diff --git a/src/main/java/org/apache/accumulo/access/AeNode.java
b/src/main/java/org/apache/accumulo/access/AeNode.java
index 65023b4..dc04f6f 100644
--- a/src/main/java/org/apache/accumulo/access/AeNode.java
+++ b/src/main/java/org/apache/accumulo/access/AeNode.java
@@ -18,6 +18,9 @@
*/
package org.apache.accumulo.access;
+import static org.apache.accumulo.access.ByteUtils.AND_OPERATOR;
+import static org.apache.accumulo.access.ByteUtils.OR_OPERATOR;
+
import java.util.List;
import java.util.TreeSet;
import java.util.function.Consumer;
@@ -300,9 +303,9 @@ abstract class AeNode implements Comparable<AeNode> {
static AeNode of(byte operator, List<AeNode> children) {
switch (operator) {
- case '&':
+ case AND_OPERATOR:
return new AndNode(children);
- case '|':
+ case OR_OPERATOR:
return new OrNode(children);
default:
throw new IllegalArgumentException();
diff --git a/src/main/java/org/apache/accumulo/access/Authorizations.java
b/src/main/java/org/apache/accumulo/access/Authorizations.java
index cbeccb9..33f3f87 100644
--- a/src/main/java/org/apache/accumulo/access/Authorizations.java
+++ b/src/main/java/org/apache/accumulo/access/Authorizations.java
@@ -22,6 +22,7 @@ import java.util.Collection;
import java.util.Set;
/**
+ * A collection of authorization strings.
*
* @since 1.0.0
*/
diff --git a/src/main/java/org/apache/accumulo/access/ByteUtils.java
b/src/main/java/org/apache/accumulo/access/ByteUtils.java
new file mode 100644
index 0000000..4f75410
--- /dev/null
+++ b/src/main/java/org/apache/accumulo/access/ByteUtils.java
@@ -0,0 +1,58 @@
+/*
+ * 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
+ *
+ * https://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.accumulo.access;
+
+/**
+ * This class exists to avoid repeat conversions from byte to char as well as
to provide helper
+ * methods for comparing them.
+ */
+public final class ByteUtils {
+ public static final byte QUOTE = (byte) '"';
+ public static final byte BACKSLASH = (byte) '\\';
+ public static final byte AND_OPERATOR = (byte) '&';
+ public static final byte OR_OPERATOR = (byte) '|';
+
+ private ByteUtils() {
+ // private constructor to prevent instantiation
+ }
+
+ public static boolean isQuoteSymbol(byte b) {
+ return b == QUOTE;
+ }
+
+ public static boolean isBackslashSymbol(byte b) {
+ return b == BACKSLASH;
+ }
+
+ public static boolean isQuoteOrSlash(byte b) {
+ return isQuoteSymbol(b) || isBackslashSymbol(b);
+ }
+
+ public static boolean isAndOperator(byte b) {
+ return b == AND_OPERATOR;
+ }
+
+ public static boolean isOrOperator(byte b) {
+ return b == OR_OPERATOR;
+ }
+
+ public static boolean isAndOrOperator(byte b) {
+ return isAndOperator(b) || isOrOperator(b);
+ }
+}
diff --git a/src/main/java/org/apache/accumulo/access/BytesWrapper.java
b/src/main/java/org/apache/accumulo/access/BytesWrapper.java
index ff5bb07..998a452 100644
--- a/src/main/java/org/apache/accumulo/access/BytesWrapper.java
+++ b/src/main/java/org/apache/accumulo/access/BytesWrapper.java
@@ -53,9 +53,17 @@ class BytesWrapper implements Comparable<BytesWrapper> {
*/
public BytesWrapper(byte[] data, int offset, int length) {
- if (offset < 0 || offset > data.length || length < 0 || (offset + length)
> data.length) {
- throw new IllegalArgumentException(" Bad offset and/or length
data.length = " + data.length
- + " offset = " + offset + " length = " + length);
+ if (offset < 0 || offset > data.length) {
+ throw new IllegalArgumentException(
+ "Offset out of bounds. data.length = " + data.length + ", offset = "
+ offset);
+ }
+ if (length < 0) {
+ throw new IllegalArgumentException("Length cannot be negative. length =
" + length);
+ }
+ if ((offset + length) > data.length) {
+ throw new IllegalArgumentException(
+ "Sum of offset and length exceeds data length. data.length = " +
data.length
+ + ", offset = " + offset + ", length = " + length);
}
this.data = data;
diff --git a/src/main/java/org/apache/accumulo/access/Parser.java
b/src/main/java/org/apache/accumulo/access/Parser.java
index 8eb822e..17b7f7a 100644
--- a/src/main/java/org/apache/accumulo/access/Parser.java
+++ b/src/main/java/org/apache/accumulo/access/Parser.java
@@ -18,12 +18,18 @@
*/
package org.apache.accumulo.access;
+import static org.apache.accumulo.access.ByteUtils.isAndOrOperator;
+
import java.util.ArrayList;
/**
* Code for parsing an access expression and creating a parse tree of type
{@link AeNode}
*/
final class Parser {
+
+ public static final byte OPEN_PAREN = (byte) '(';
+ public static final byte CLOSE_PAREN = (byte) ')';
+
public static AeNode parseAccessExpression(byte[] expression) {
Tokenizer tokenizer = new Tokenizer(expression);
@@ -46,7 +52,7 @@ final class Parser {
AeNode first = parseParenExpressionOrAuthorization(tokenizer);
- if (tokenizer.hasNext() && (tokenizer.peek() == '&' || tokenizer.peek() ==
'|')) {
+ if (tokenizer.hasNext() && isAndOrOperator(tokenizer.peek())) {
var nodes = new ArrayList<AeNode>();
nodes.add(first);
@@ -59,7 +65,7 @@ final class Parser {
} while (tokenizer.hasNext() && tokenizer.peek() == operator);
- if (tokenizer.hasNext() && (tokenizer.peek() == '|' || tokenizer.peek()
== '&')) {
+ if (tokenizer.hasNext() && isAndOrOperator(tokenizer.peek())) {
// A case of mixed operators, lets give a clear error message
tokenizer.error("Cannot mix '|' and '&'");
}
@@ -76,10 +82,10 @@ final class Parser {
.error("Expected a '(' character or an authorization token instead
saw end of input");
}
- if (tokenizer.peek() == '(') {
+ if (tokenizer.peek() == OPEN_PAREN) {
tokenizer.advance();
var node = parseExpression(tokenizer);
- tokenizer.next(')');
+ tokenizer.next(CLOSE_PAREN);
return node;
} else {
return AeNode.of(tokenizer.nextAuthorization());
diff --git a/src/main/java/org/apache/accumulo/access/Tokenizer.java
b/src/main/java/org/apache/accumulo/access/Tokenizer.java
index de5e21f..b5e3f14 100644
--- a/src/main/java/org/apache/accumulo/access/Tokenizer.java
+++ b/src/main/java/org/apache/accumulo/access/Tokenizer.java
@@ -19,6 +19,11 @@
package org.apache.accumulo.access;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.accumulo.access.ByteUtils.isBackslashSymbol;
+import static org.apache.accumulo.access.ByteUtils.isQuoteOrSlash;
+import static org.apache.accumulo.access.ByteUtils.isQuoteSymbol;
+
+import java.util.stream.IntStream;
/**
* A simple wrapper around a byte array that keeps some state and provides
high level operations to
@@ -30,37 +35,24 @@ final class Tokenizer {
private static final boolean[] validAuthChars = new boolean[256];
static {
- for (int i = 0; i < 256; i++) {
- validAuthChars[i] = false;
- }
-
- for (int i = 'a'; i <= 'z'; i++) {
- validAuthChars[i] = true;
- }
+ IntStream.range(0, 256).forEach(i -> validAuthChars[i] = false);
- for (int i = 'A'; i <= 'Z'; i++) {
- validAuthChars[i] = true;
- }
-
- for (int i = '0'; i <= '9'; i++) {
- validAuthChars[i] = true;
- }
+ IntStream numbers = IntStream.rangeClosed('0', '9');
+ IntStream letters =
+ IntStream.concat(IntStream.rangeClosed('A', 'Z'),
IntStream.rangeClosed('a', 'z'));
+ IntStream.concat(numbers, letters).forEach(i -> validAuthChars[i] = true);
- validAuthChars['_'] = true;
- validAuthChars['-'] = true;
- validAuthChars[':'] = true;
- validAuthChars['.'] = true;
- validAuthChars['/'] = true;
+ "_-:./".chars().forEach(c -> validAuthChars[c] = true);
}
static boolean isValidAuthChar(byte b) {
return validAuthChars[0xff & b];
}
- private byte[] expression;
+ private final byte[] expression;
private int index;
- private AuthorizationToken authorizationToken = new AuthorizationToken();
+ private final AuthorizationToken authorizationToken = new
AuthorizationToken();
static class AuthorizationToken {
byte[] data;
@@ -81,13 +73,13 @@ final class Tokenizer {
index++;
}
- public void next(char expected) {
+ public void next(byte expected) {
if (!hasNext()) {
- error("Expected '" + expected + "' instead saw end of input");
+ error("Expected '" + (char) expected + "' instead saw end of input");
}
if (expression[index] != expected) {
- error("Expected '" + expected + "' instead saw '" + (char)
(expression[index]) + "'");
+ error("Expected '" + (char) expected + "' instead saw '" + (char)
(expression[index]) + "'");
}
index++;
}
@@ -105,14 +97,13 @@ final class Tokenizer {
}
AuthorizationToken nextAuthorization() {
- if (expression[index] == '"') {
+ if (isQuoteSymbol(expression[index])) {
int start = ++index;
- while (index < expression.length && expression[index] != '"') {
- if (expression[index] == '\\') {
+ while (index < expression.length && !isQuoteSymbol(expression[index])) {
+ if (isBackslashSymbol(expression[index])) {
index++;
- if (index == expression.length
- || (expression[index] != '\\' && expression[index] != '"')) {
+ if (index == expression.length ||
!isQuoteOrSlash(expression[index])) {
error("Invalid escaping within quotes", index - 1);
}
}