blob: b5f77e911cad80940eea5516a0e52510cc8b1e95 [file] [log] [blame]
/*
* 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.ignite.spi.deployment.uri;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.internal.S;
/**
* Helper class which encodes given string.
* It replaces all occurrences of space with '%20', percent sign
* with '%25' and semicolon with '%3B' if given string corresponds to
* expected format.
* <p>
* Expected format is (schema):(//)URL(?|#)(parameters)
*/
class GridUriDeploymentUriParser {
/** Input string which should be parsed and encoded. */
private final String input;
/** Encoded string. */
@GridToStringExclude private String encoded;
/**
* Creates new instance of parser for the given input string.
*
* @param input Input string which will be parsed.
*/
GridUriDeploymentUriParser(String input) {
assert input != null;
this.input = input;
encoded = input;
}
/**
* Parses {@link #input} by extracting URL without schema and parameters
* and than encodes this URL.
* <p>
* Expected {@link #input} format is (schema):(//)URL(?|#)(parameters)
*
* @return Either encoded string or unchanged if it does not match format.
*/
String parse() {
int n = input.length();
// Scheme.
int p = scan(0, n, "/?#", ":");
if (p > 0 && at(p, n, ':')) {
p++; // Skip ':'
if (at(p, n, '/')) {
if (at(p, n, '/') && at(p + 1, n, '/')) {
p += 2;
// Seek authority.
int q = scan(p, n, "", "/?#");
if (q > p)
p = q;
}
int q = scan(p, n, "", "?#");
StringBuilder buf = new StringBuilder(input.substring(0, p));
buf.append(encodePath(input.substring(p, q)));
buf.append(input.substring(q, n));
encoded = buf.toString();
}
}
return encoded;
}
/**
* Scan forward from the given start position. Stop at the first char
* in the err string (in which case -1 is returned), or the first char
* in the stop string (in which case the index of the preceding char is
* returned), or the end of the input string (in which case the length
* of the input string is returned). May return the start position if
* none matches.
*
* @param start Start scan position.
* @param end End scan position.
* @param err Error characters.
* @param stop Stoppers.
* @return {@code -1} if character from the error characters list was found;
* index of first character occurrence is on stop character list; end
* position if {@link #input} does not contain any characters
* from {@code error} or {@code stop}; start if start > end.
*/
private int scan(int start, int end, String err, String stop) {
int p = start;
while (p < end) {
char c = input.charAt(p);
if (err.indexOf(c) >= 0)
return -1;
if (stop.indexOf(c) >= 0)
break;
p++;
}
return p;
}
/**
* Tests whether {@link #input} contains {@code c} at position {@code start}
* and {@code start} less than {@code end}.
*
* @param start Start position.
* @param end End position.
* @param c Character {@link #input} is tested against
* @return {@code true} only if {@link #input} contains {@code c} at position
* {@code start} and {@code start} less than {@code end}.
*/
private boolean at(int start, int end, char c) {
return start < end && input.charAt(start) == c;
}
/**
* Encodes given path by replacing all occurrences of space with '%20',
* percent sign with '%25' and semicolon with '%3B'.
*
* @param path Path to be encoded.
* @return Encoded path.
*/
private String encodePath(String path) {
StringBuilder buf = new StringBuilder(path.length());
for (int i = 0; i < path.length(); i++) {
char c = path.charAt(i);
switch (c) {
case ' ': {
buf.append("%20"); break;
}
case '%': {
buf.append("%25"); break;
}
case ';': {
buf.append("%3B"); break;
}
default: {
buf.append(c);
}
}
}
return buf.toString();
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(GridUriDeploymentUriParser.class, this);
}
}