914 lines
31 KiB
Java
914 lines
31 KiB
Java
/*
|
|
* Copyright (C) 2007 The Android Open Source Project
|
|
*
|
|
* Licensed 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 android.net;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.StringTokenizer;
|
|
|
|
/**
|
|
*
|
|
* Sanitizes the Query portion of a URL. Simple example:
|
|
* <code>
|
|
* UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
|
|
* sanitizer.setAllowUnregisteredParamaters(true);
|
|
* sanitizer.parseUrl("http://example.com/?name=Joe+User");
|
|
* String name = sanitizer.getValue("name"));
|
|
* // name now contains "Joe_User"
|
|
* </code>
|
|
*
|
|
* Register ValueSanitizers to customize the way individual
|
|
* parameters are sanitized:
|
|
* <code>
|
|
* UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
|
|
* sanitizer.registerParamater("name", UrlQuerySanitizer.createSpaceLegal());
|
|
* sanitizer.parseUrl("http://example.com/?name=Joe+User");
|
|
* String name = sanitizer.getValue("name"));
|
|
* // name now contains "Joe User". (The string is first decoded, which
|
|
* // converts the '+' to a ' '. Then the string is sanitized, which
|
|
* // converts the ' ' to an '_'. (The ' ' is converted because the default
|
|
* unregistered parameter sanitizer does not allow any special characters,
|
|
* and ' ' is a special character.)
|
|
* </code>
|
|
*
|
|
* There are several ways to create ValueSanitizers. In order of increasing
|
|
* sophistication:
|
|
* <ol>
|
|
* <li>Call one of the UrlQuerySanitizer.createXXX() methods.
|
|
* <li>Construct your own instance of
|
|
* UrlQuerySanitizer.IllegalCharacterValueSanitizer.
|
|
* <li>Subclass UrlQuerySanitizer.ValueSanitizer to define your own value
|
|
* sanitizer.
|
|
* </ol>
|
|
*
|
|
*/
|
|
public class UrlQuerySanitizer {
|
|
|
|
/**
|
|
* A simple tuple that holds parameter-value pairs.
|
|
*
|
|
*/
|
|
public class ParameterValuePair {
|
|
/**
|
|
* Construct a parameter-value tuple.
|
|
* @param parameter an unencoded parameter
|
|
* @param value an unencoded value
|
|
*/
|
|
public ParameterValuePair(String parameter,
|
|
String value) {
|
|
mParameter = parameter;
|
|
mValue = value;
|
|
}
|
|
/**
|
|
* The unencoded parameter
|
|
*/
|
|
public String mParameter;
|
|
/**
|
|
* The unencoded value
|
|
*/
|
|
public String mValue;
|
|
}
|
|
|
|
final private HashMap<String, ValueSanitizer> mSanitizers =
|
|
new HashMap<String, ValueSanitizer>();
|
|
final private HashMap<String, String> mEntries =
|
|
new HashMap<String, String>();
|
|
final private ArrayList<ParameterValuePair> mEntriesList =
|
|
new ArrayList<ParameterValuePair>();
|
|
private boolean mAllowUnregisteredParamaters;
|
|
private boolean mPreferFirstRepeatedParameter;
|
|
private ValueSanitizer mUnregisteredParameterValueSanitizer =
|
|
getAllIllegal();
|
|
|
|
/**
|
|
* A functor used to sanitize a single query value.
|
|
*
|
|
*/
|
|
public static interface ValueSanitizer {
|
|
/**
|
|
* Sanitize an unencoded value.
|
|
* @param value
|
|
* @return the sanitized unencoded value
|
|
*/
|
|
public String sanitize(String value);
|
|
}
|
|
|
|
/**
|
|
* Sanitize values based on which characters they contain. Illegal
|
|
* characters are replaced with either space or '_', depending upon
|
|
* whether space is a legal character or not.
|
|
*/
|
|
public static class IllegalCharacterValueSanitizer implements
|
|
ValueSanitizer {
|
|
private int mFlags;
|
|
|
|
/**
|
|
* Allow space (' ') characters.
|
|
*/
|
|
public final static int SPACE_OK = 1 << 0;
|
|
/**
|
|
* Allow whitespace characters other than space. The
|
|
* other whitespace characters are
|
|
* '\t' '\f' '\n' '\r' and '\0x000b' (vertical tab)
|
|
*/
|
|
public final static int OTHER_WHITESPACE_OK = 1 << 1;
|
|
/**
|
|
* Allow characters with character codes 128 to 255.
|
|
*/
|
|
public final static int NON_7_BIT_ASCII_OK = 1 << 2;
|
|
/**
|
|
* Allow double quote characters. ('"')
|
|
*/
|
|
public final static int DQUOTE_OK = 1 << 3;
|
|
/**
|
|
* Allow single quote characters. ('\'')
|
|
*/
|
|
public final static int SQUOTE_OK = 1 << 4;
|
|
/**
|
|
* Allow less-than characters. ('<')
|
|
*/
|
|
public final static int LT_OK = 1 << 5;
|
|
/**
|
|
* Allow greater-than characters. ('>')
|
|
*/
|
|
public final static int GT_OK = 1 << 6;
|
|
/**
|
|
* Allow ampersand characters ('&')
|
|
*/
|
|
public final static int AMP_OK = 1 << 7;
|
|
/**
|
|
* Allow percent-sign characters ('%')
|
|
*/
|
|
public final static int PCT_OK = 1 << 8;
|
|
/**
|
|
* Allow nul characters ('\0')
|
|
*/
|
|
public final static int NUL_OK = 1 << 9;
|
|
/**
|
|
* Allow text to start with a script URL
|
|
* such as "javascript:" or "vbscript:"
|
|
*/
|
|
public final static int SCRIPT_URL_OK = 1 << 10;
|
|
|
|
/**
|
|
* Mask with all fields set to OK
|
|
*/
|
|
public final static int ALL_OK = 0x7ff;
|
|
|
|
/**
|
|
* Mask with both regular space and other whitespace OK
|
|
*/
|
|
public final static int ALL_WHITESPACE_OK =
|
|
SPACE_OK | OTHER_WHITESPACE_OK;
|
|
|
|
|
|
// Common flag combinations:
|
|
|
|
/**
|
|
* <ul>
|
|
* <li>Deny all special characters.
|
|
* <li>Deny script URLs.
|
|
* </ul>
|
|
*/
|
|
public final static int ALL_ILLEGAL =
|
|
0;
|
|
/**
|
|
* <ul>
|
|
* <li>Allow all special characters except Nul. ('\0').
|
|
* <li>Allow script URLs.
|
|
* </ul>
|
|
*/
|
|
public final static int ALL_BUT_NUL_LEGAL =
|
|
ALL_OK & ~NUL_OK;
|
|
/**
|
|
* <ul>
|
|
* <li>Allow all special characters except for:
|
|
* <ul>
|
|
* <li>whitespace characters
|
|
* <li>Nul ('\0')
|
|
* </ul>
|
|
* <li>Allow script URLs.
|
|
* </ul>
|
|
*/
|
|
public final static int ALL_BUT_WHITESPACE_LEGAL =
|
|
ALL_OK & ~(ALL_WHITESPACE_OK | NUL_OK);
|
|
/**
|
|
* <ul>
|
|
* <li>Allow characters used by encoded URLs.
|
|
* <li>Deny script URLs.
|
|
* </ul>
|
|
*/
|
|
public final static int URL_LEGAL =
|
|
NON_7_BIT_ASCII_OK | SQUOTE_OK | AMP_OK | PCT_OK;
|
|
/**
|
|
* <ul>
|
|
* <li>Allow characters used by encoded URLs.
|
|
* <li>Allow spaces.
|
|
* <li>Deny script URLs.
|
|
* </ul>
|
|
*/
|
|
public final static int URL_AND_SPACE_LEGAL =
|
|
URL_LEGAL | SPACE_OK;
|
|
/**
|
|
* <ul>
|
|
* <li>Allow ampersand.
|
|
* <li>Deny script URLs.
|
|
* </ul>
|
|
*/
|
|
public final static int AMP_LEGAL =
|
|
AMP_OK;
|
|
/**
|
|
* <ul>
|
|
* <li>Allow ampersand.
|
|
* <li>Allow space.
|
|
* <li>Deny script URLs.
|
|
* </ul>
|
|
*/
|
|
public final static int AMP_AND_SPACE_LEGAL =
|
|
AMP_OK | SPACE_OK;
|
|
/**
|
|
* <ul>
|
|
* <li>Allow space.
|
|
* <li>Deny script URLs.
|
|
* </ul>
|
|
*/
|
|
public final static int SPACE_LEGAL =
|
|
SPACE_OK;
|
|
/**
|
|
* <ul>
|
|
* <li>Allow all but.
|
|
* <ul>
|
|
* <li>Nul ('\0')
|
|
* <li>Angle brackets ('<', '>')
|
|
* </ul>
|
|
* <li>Deny script URLs.
|
|
* </ul>
|
|
*/
|
|
public final static int ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL =
|
|
ALL_OK & ~(NUL_OK | LT_OK | GT_OK);
|
|
|
|
/**
|
|
* Script URL definitions
|
|
*/
|
|
|
|
private final static String JAVASCRIPT_PREFIX = "javascript:";
|
|
|
|
private final static String VBSCRIPT_PREFIX = "vbscript:";
|
|
|
|
private final static int MIN_SCRIPT_PREFIX_LENGTH = Math.min(
|
|
JAVASCRIPT_PREFIX.length(), VBSCRIPT_PREFIX.length());
|
|
|
|
/**
|
|
* Construct a sanitizer. The parameters set the behavior of the
|
|
* sanitizer.
|
|
* @param flags some combination of the XXX_OK flags.
|
|
*/
|
|
public IllegalCharacterValueSanitizer(
|
|
int flags) {
|
|
mFlags = flags;
|
|
}
|
|
/**
|
|
* Sanitize a value.
|
|
* <ol>
|
|
* <li>If script URLs are not OK, the will be removed.
|
|
* <li>If neither spaces nor other white space is OK, then
|
|
* white space will be trimmed from the beginning and end of
|
|
* the URL. (Just the actual white space characters are trimmed, not
|
|
* other control codes.)
|
|
* <li> Illegal characters will be replaced with
|
|
* either ' ' or '_', depending on whether a space is itself a
|
|
* legal character.
|
|
* </ol>
|
|
* @param value
|
|
* @return the sanitized value
|
|
*/
|
|
public String sanitize(String value) {
|
|
if (value == null) {
|
|
return null;
|
|
}
|
|
int length = value.length();
|
|
if ((mFlags & SCRIPT_URL_OK) != 0) {
|
|
if (length >= MIN_SCRIPT_PREFIX_LENGTH) {
|
|
String asLower = value.toLowerCase();
|
|
if (asLower.startsWith(JAVASCRIPT_PREFIX) ||
|
|
asLower.startsWith(VBSCRIPT_PREFIX)) {
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
|
|
// If whitespace isn't OK, get rid of whitespace at beginning
|
|
// and end of value.
|
|
if ( (mFlags & ALL_WHITESPACE_OK) == 0) {
|
|
value = trimWhitespace(value);
|
|
// The length could have changed, so we need to correct
|
|
// the length variable.
|
|
length = value.length();
|
|
}
|
|
|
|
StringBuilder stringBuilder = new StringBuilder(length);
|
|
for(int i = 0; i < length; i++) {
|
|
char c = value.charAt(i);
|
|
if (!characterIsLegal(c)) {
|
|
if ((mFlags & SPACE_OK) != 0) {
|
|
c = ' ';
|
|
}
|
|
else {
|
|
c = '_';
|
|
}
|
|
}
|
|
stringBuilder.append(c);
|
|
}
|
|
return stringBuilder.toString();
|
|
}
|
|
|
|
/**
|
|
* Trim whitespace from the beginning and end of a string.
|
|
* <p>
|
|
* Note: can't use {@link String#trim} because {@link String#trim} has a
|
|
* different definition of whitespace than we want.
|
|
* @param value the string to trim
|
|
* @return the trimmed string
|
|
*/
|
|
private String trimWhitespace(String value) {
|
|
int start = 0;
|
|
int last = value.length() - 1;
|
|
int end = last;
|
|
while (start <= end && isWhitespace(value.charAt(start))) {
|
|
start++;
|
|
}
|
|
while (end >= start && isWhitespace(value.charAt(end))) {
|
|
end--;
|
|
}
|
|
if (start == 0 && end == last) {
|
|
return value;
|
|
}
|
|
return value.substring(start, end + 1);
|
|
}
|
|
|
|
/**
|
|
* Check if c is whitespace.
|
|
* @param c character to test
|
|
* @return true if c is a whitespace character
|
|
*/
|
|
private boolean isWhitespace(char c) {
|
|
switch(c) {
|
|
case ' ':
|
|
case '\t':
|
|
case '\f':
|
|
case '\n':
|
|
case '\r':
|
|
case 11: /* VT */
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check whether an individual character is legal. Uses the
|
|
* flag bit-set passed into the constructor.
|
|
* @param c
|
|
* @return true if c is a legal character
|
|
*/
|
|
private boolean characterIsLegal(char c) {
|
|
switch(c) {
|
|
case ' ' : return (mFlags & SPACE_OK) != 0;
|
|
case '\t': case '\f': case '\n': case '\r': case 11: /* VT */
|
|
return (mFlags & OTHER_WHITESPACE_OK) != 0;
|
|
case '\"': return (mFlags & DQUOTE_OK) != 0;
|
|
case '\'': return (mFlags & SQUOTE_OK) != 0;
|
|
case '<' : return (mFlags & LT_OK) != 0;
|
|
case '>' : return (mFlags & GT_OK) != 0;
|
|
case '&' : return (mFlags & AMP_OK) != 0;
|
|
case '%' : return (mFlags & PCT_OK) != 0;
|
|
case '\0': return (mFlags & NUL_OK) != 0;
|
|
default : return (c >= 32 && c < 127) ||
|
|
((c >= 128) && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the current value sanitizer used when processing
|
|
* unregistered parameter values.
|
|
* <p>
|
|
* <b>Note:</b> The default unregistered parameter value sanitizer is
|
|
* one that doesn't allow any special characters, similar to what
|
|
* is returned by calling createAllIllegal.
|
|
*
|
|
* @return the current ValueSanitizer used to sanitize unregistered
|
|
* parameter values.
|
|
*/
|
|
public ValueSanitizer getUnregisteredParameterValueSanitizer() {
|
|
return mUnregisteredParameterValueSanitizer;
|
|
}
|
|
|
|
/**
|
|
* Set the value sanitizer used when processing unregistered
|
|
* parameter values.
|
|
* @param sanitizer set the ValueSanitizer used to sanitize unregistered
|
|
* parameter values.
|
|
*/
|
|
public void setUnregisteredParameterValueSanitizer(
|
|
ValueSanitizer sanitizer) {
|
|
mUnregisteredParameterValueSanitizer = sanitizer;
|
|
}
|
|
|
|
|
|
// Private fields for singleton sanitizers:
|
|
|
|
private static final ValueSanitizer sAllIllegal =
|
|
new IllegalCharacterValueSanitizer(
|
|
IllegalCharacterValueSanitizer.ALL_ILLEGAL);
|
|
|
|
private static final ValueSanitizer sAllButNulLegal =
|
|
new IllegalCharacterValueSanitizer(
|
|
IllegalCharacterValueSanitizer.ALL_BUT_NUL_LEGAL);
|
|
|
|
private static final ValueSanitizer sAllButWhitespaceLegal =
|
|
new IllegalCharacterValueSanitizer(
|
|
IllegalCharacterValueSanitizer.ALL_BUT_WHITESPACE_LEGAL);
|
|
|
|
private static final ValueSanitizer sURLLegal =
|
|
new IllegalCharacterValueSanitizer(
|
|
IllegalCharacterValueSanitizer.URL_LEGAL);
|
|
|
|
private static final ValueSanitizer sUrlAndSpaceLegal =
|
|
new IllegalCharacterValueSanitizer(
|
|
IllegalCharacterValueSanitizer.URL_AND_SPACE_LEGAL);
|
|
|
|
private static final ValueSanitizer sAmpLegal =
|
|
new IllegalCharacterValueSanitizer(
|
|
IllegalCharacterValueSanitizer.AMP_LEGAL);
|
|
|
|
private static final ValueSanitizer sAmpAndSpaceLegal =
|
|
new IllegalCharacterValueSanitizer(
|
|
IllegalCharacterValueSanitizer.AMP_AND_SPACE_LEGAL);
|
|
|
|
private static final ValueSanitizer sSpaceLegal =
|
|
new IllegalCharacterValueSanitizer(
|
|
IllegalCharacterValueSanitizer.SPACE_LEGAL);
|
|
|
|
private static final ValueSanitizer sAllButNulAndAngleBracketsLegal =
|
|
new IllegalCharacterValueSanitizer(
|
|
IllegalCharacterValueSanitizer.ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL);
|
|
|
|
/**
|
|
* Return a value sanitizer that does not allow any special characters,
|
|
* and also does not allow script URLs.
|
|
* @return a value sanitizer
|
|
*/
|
|
public static final ValueSanitizer getAllIllegal() {
|
|
return sAllIllegal;
|
|
}
|
|
|
|
/**
|
|
* Return a value sanitizer that allows everything except Nul ('\0')
|
|
* characters. Script URLs are allowed.
|
|
* @return a value sanitizer
|
|
*/
|
|
public static final ValueSanitizer getAllButNulLegal() {
|
|
return sAllButNulLegal;
|
|
}
|
|
/**
|
|
* Return a value sanitizer that allows everything except Nul ('\0')
|
|
* characters, space (' '), and other whitespace characters.
|
|
* Script URLs are allowed.
|
|
* @return a value sanitizer
|
|
*/
|
|
public static final ValueSanitizer getAllButWhitespaceLegal() {
|
|
return sAllButWhitespaceLegal;
|
|
}
|
|
/**
|
|
* Return a value sanitizer that allows all the characters used by
|
|
* encoded URLs. Does not allow script URLs.
|
|
* @return a value sanitizer
|
|
*/
|
|
public static final ValueSanitizer getUrlLegal() {
|
|
return sURLLegal;
|
|
}
|
|
/**
|
|
* Return a value sanitizer that allows all the characters used by
|
|
* encoded URLs and allows spaces, which are not technically legal
|
|
* in encoded URLs, but commonly appear anyway.
|
|
* Does not allow script URLs.
|
|
* @return a value sanitizer
|
|
*/
|
|
public static final ValueSanitizer getUrlAndSpaceLegal() {
|
|
return sUrlAndSpaceLegal;
|
|
}
|
|
/**
|
|
* Return a value sanitizer that does not allow any special characters
|
|
* except ampersand ('&'). Does not allow script URLs.
|
|
* @return a value sanitizer
|
|
*/
|
|
public static final ValueSanitizer getAmpLegal() {
|
|
return sAmpLegal;
|
|
}
|
|
/**
|
|
* Return a value sanitizer that does not allow any special characters
|
|
* except ampersand ('&') and space (' '). Does not allow script URLs.
|
|
* @return a value sanitizer
|
|
*/
|
|
public static final ValueSanitizer getAmpAndSpaceLegal() {
|
|
return sAmpAndSpaceLegal;
|
|
}
|
|
/**
|
|
* Return a value sanitizer that does not allow any special characters
|
|
* except space (' '). Does not allow script URLs.
|
|
* @return a value sanitizer
|
|
*/
|
|
public static final ValueSanitizer getSpaceLegal() {
|
|
return sSpaceLegal;
|
|
}
|
|
/**
|
|
* Return a value sanitizer that allows any special characters
|
|
* except angle brackets ('<' and '>') and Nul ('\0').
|
|
* Allows script URLs.
|
|
* @return a value sanitizer
|
|
*/
|
|
public static final ValueSanitizer getAllButNulAndAngleBracketsLegal() {
|
|
return sAllButNulAndAngleBracketsLegal;
|
|
}
|
|
|
|
/**
|
|
* Constructs a UrlQuerySanitizer.
|
|
* <p>
|
|
* Defaults:
|
|
* <ul>
|
|
* <li>unregistered parameters are not allowed.
|
|
* <li>the last instance of a repeated parameter is preferred.
|
|
* <li>The default value sanitizer is an AllIllegal value sanitizer.
|
|
* <ul>
|
|
*/
|
|
public UrlQuerySanitizer() {
|
|
}
|
|
|
|
/**
|
|
* Constructs a UrlQuerySanitizer and parse a URL.
|
|
* This constructor is provided for convenience when the
|
|
* default parsing behavior is acceptable.
|
|
* <p>
|
|
* Because the URL is parsed before the constructor returns, there isn't
|
|
* a chance to configure the sanitizer to change the parsing behavior.
|
|
* <p>
|
|
* <code>
|
|
* UrlQuerySanitizer sanitizer = new UrlQuerySanitizer(myUrl);
|
|
* String name = sanitizer.getValue("name");
|
|
* </code>
|
|
* <p>
|
|
* Defaults:
|
|
* <ul>
|
|
* <li>unregistered parameters <em>are</em> allowed.
|
|
* <li>the last instance of a repeated parameter is preferred.
|
|
* <li>The default value sanitizer is an AllIllegal value sanitizer.
|
|
* <ul>
|
|
*/
|
|
public UrlQuerySanitizer(String url) {
|
|
setAllowUnregisteredParamaters(true);
|
|
parseUrl(url);
|
|
}
|
|
|
|
/**
|
|
* Parse the query parameters out of an encoded URL.
|
|
* Works by extracting the query portion from the URL and then
|
|
* calling parseQuery(). If there is no query portion it is
|
|
* treated as if the query portion is an empty string.
|
|
* @param url the encoded URL to parse.
|
|
*/
|
|
public void parseUrl(String url) {
|
|
int queryIndex = url.indexOf('?');
|
|
String query;
|
|
if (queryIndex >= 0) {
|
|
query = url.substring(queryIndex + 1);
|
|
}
|
|
else {
|
|
query = "";
|
|
}
|
|
parseQuery(query);
|
|
}
|
|
|
|
/**
|
|
* Parse a query. A query string is any number of parameter-value clauses
|
|
* separated by any non-zero number of ampersands. A parameter-value clause
|
|
* is a parameter followed by an equal sign, followed by a value. If the
|
|
* equal sign is missing, the value is assumed to be the empty string.
|
|
* @param query the query to parse.
|
|
*/
|
|
public void parseQuery(String query) {
|
|
clear();
|
|
// Split by '&'
|
|
StringTokenizer tokenizer = new StringTokenizer(query, "&");
|
|
while(tokenizer.hasMoreElements()) {
|
|
String attributeValuePair = tokenizer.nextToken();
|
|
if (attributeValuePair.length() > 0) {
|
|
int assignmentIndex = attributeValuePair.indexOf('=');
|
|
if (assignmentIndex < 0) {
|
|
// No assignment found, treat as if empty value
|
|
parseEntry(attributeValuePair, "");
|
|
}
|
|
else {
|
|
parseEntry(attributeValuePair.substring(0, assignmentIndex),
|
|
attributeValuePair.substring(assignmentIndex + 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a set of all of the parameters found in the sanitized query.
|
|
* <p>
|
|
* Note: Do not modify this set. Treat it as a read-only set.
|
|
* @return all the parameters found in the current query.
|
|
*/
|
|
public Set<String> getParameterSet() {
|
|
return mEntries.keySet();
|
|
}
|
|
|
|
/**
|
|
* An array list of all of the parameter value pairs in the sanitized
|
|
* query, in the order they appeared in the query. May contain duplicate
|
|
* parameters.
|
|
* <p class="note"><b>Note:</b> Do not modify this list. Treat it as a read-only list.</p>
|
|
*/
|
|
public List<ParameterValuePair> getParameterList() {
|
|
return mEntriesList;
|
|
}
|
|
|
|
/**
|
|
* Check if a parameter exists in the current sanitized query.
|
|
* @param parameter the unencoded name of a parameter.
|
|
* @return true if the paramater exists in the current sanitized queary.
|
|
*/
|
|
public boolean hasParameter(String parameter) {
|
|
return mEntries.containsKey(parameter);
|
|
}
|
|
|
|
/**
|
|
* Get the value for a parameter in the current sanitized query.
|
|
* Returns null if the parameter does not
|
|
* exit.
|
|
* @param parameter the unencoded name of a parameter.
|
|
* @return the sanitized unencoded value of the parameter,
|
|
* or null if the parameter does not exist.
|
|
*/
|
|
public String getValue(String parameter) {
|
|
return mEntries.get(parameter);
|
|
}
|
|
|
|
/**
|
|
* Register a value sanitizer for a particular parameter. Can also be used
|
|
* to replace or remove an already-set value sanitizer.
|
|
* <p>
|
|
* Registering a non-null value sanitizer for a particular parameter
|
|
* makes that parameter a registered parameter.
|
|
* @param parameter an unencoded parameter name
|
|
* @param valueSanitizer the value sanitizer to use for a particular
|
|
* parameter. May be null in order to unregister that parameter.
|
|
* @see #getAllowUnregisteredParamaters()
|
|
*/
|
|
public void registerParameter(String parameter,
|
|
ValueSanitizer valueSanitizer) {
|
|
if (valueSanitizer == null) {
|
|
mSanitizers.remove(parameter);
|
|
}
|
|
mSanitizers.put(parameter, valueSanitizer);
|
|
}
|
|
|
|
/**
|
|
* Register a value sanitizer for an array of parameters.
|
|
* @param parameters An array of unencoded parameter names.
|
|
* @param valueSanitizer
|
|
* @see #registerParameter
|
|
*/
|
|
public void registerParameters(String[] parameters,
|
|
ValueSanitizer valueSanitizer) {
|
|
int length = parameters.length;
|
|
for(int i = 0; i < length; i++) {
|
|
mSanitizers.put(parameters[i], valueSanitizer);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set whether or not unregistered parameters are allowed. If they
|
|
* are not allowed, then they will be dropped when a query is sanitized.
|
|
* <p>
|
|
* Defaults to false.
|
|
* @param allowUnregisteredParamaters true to allow unregistered parameters.
|
|
* @see #getAllowUnregisteredParamaters()
|
|
*/
|
|
public void setAllowUnregisteredParamaters(
|
|
boolean allowUnregisteredParamaters) {
|
|
mAllowUnregisteredParamaters = allowUnregisteredParamaters;
|
|
}
|
|
|
|
/**
|
|
* Get whether or not unregistered parameters are allowed. If not
|
|
* allowed, they will be dropped when a query is parsed.
|
|
* @return true if unregistered parameters are allowed.
|
|
* @see #setAllowUnregisteredParamaters(boolean)
|
|
*/
|
|
public boolean getAllowUnregisteredParamaters() {
|
|
return mAllowUnregisteredParamaters;
|
|
}
|
|
|
|
/**
|
|
* Set whether or not the first occurrence of a repeated parameter is
|
|
* preferred. True means the first repeated parameter is preferred.
|
|
* False means that the last repeated parameter is preferred.
|
|
* <p>
|
|
* The preferred parameter is the one that is returned when getParameter
|
|
* is called.
|
|
* <p>
|
|
* defaults to false.
|
|
* @param preferFirstRepeatedParameter True if the first repeated
|
|
* parameter is preferred.
|
|
* @see #getPreferFirstRepeatedParameter()
|
|
*/
|
|
public void setPreferFirstRepeatedParameter(
|
|
boolean preferFirstRepeatedParameter) {
|
|
mPreferFirstRepeatedParameter = preferFirstRepeatedParameter;
|
|
}
|
|
|
|
/**
|
|
* Get whether or not the first occurrence of a repeated parameter is
|
|
* preferred.
|
|
* @return true if the first occurrence of a repeated parameter is
|
|
* preferred.
|
|
* @see #setPreferFirstRepeatedParameter(boolean)
|
|
*/
|
|
public boolean getPreferFirstRepeatedParameter() {
|
|
return mPreferFirstRepeatedParameter;
|
|
}
|
|
|
|
/**
|
|
* Parse an escaped parameter-value pair. The default implementation
|
|
* unescapes both the parameter and the value, then looks up the
|
|
* effective value sanitizer for the parameter and uses it to sanitize
|
|
* the value. If all goes well then addSanitizedValue is called with
|
|
* the unescaped parameter and the sanitized unescaped value.
|
|
* @param parameter an escaped parameter
|
|
* @param value an unsanitzied escaped value
|
|
*/
|
|
protected void parseEntry(String parameter, String value) {
|
|
String unescapedParameter = unescape(parameter);
|
|
ValueSanitizer valueSanitizer =
|
|
getEffectiveValueSanitizer(unescapedParameter);
|
|
|
|
if (valueSanitizer == null) {
|
|
return;
|
|
}
|
|
String unescapedValue = unescape(value);
|
|
String sanitizedValue = valueSanitizer.sanitize(unescapedValue);
|
|
addSanitizedEntry(unescapedParameter, sanitizedValue);
|
|
}
|
|
|
|
/**
|
|
* Record a sanitized parameter-value pair. Override if you want to
|
|
* do additional filtering or validation.
|
|
* @param parameter an unescaped parameter
|
|
* @param value a sanitized unescaped value
|
|
*/
|
|
protected void addSanitizedEntry(String parameter, String value) {
|
|
mEntriesList.add(
|
|
new ParameterValuePair(parameter, value));
|
|
if (mPreferFirstRepeatedParameter) {
|
|
if (mEntries.containsKey(parameter)) {
|
|
return;
|
|
}
|
|
}
|
|
mEntries.put(parameter, value);
|
|
}
|
|
|
|
/**
|
|
* Get the value sanitizer for a parameter. Returns null if there
|
|
* is no value sanitizer registered for the parameter.
|
|
* @param parameter the unescaped parameter
|
|
* @return the currently registered value sanitizer for this parameter.
|
|
* @see #registerParameter(String, android.net.UrlQuerySanitizer.ValueSanitizer)
|
|
*/
|
|
public ValueSanitizer getValueSanitizer(String parameter) {
|
|
return mSanitizers.get(parameter);
|
|
}
|
|
|
|
/**
|
|
* Get the effective value sanitizer for a parameter. Like getValueSanitizer,
|
|
* except if there is no value sanitizer registered for a parameter, and
|
|
* unregistered paramaters are allowed, then the default value sanitizer is
|
|
* returned.
|
|
* @param parameter an unescaped parameter
|
|
* @return the effective value sanitizer for a parameter.
|
|
*/
|
|
public ValueSanitizer getEffectiveValueSanitizer(String parameter) {
|
|
ValueSanitizer sanitizer = getValueSanitizer(parameter);
|
|
if (sanitizer == null && mAllowUnregisteredParamaters) {
|
|
sanitizer = getUnregisteredParameterValueSanitizer();
|
|
}
|
|
return sanitizer;
|
|
}
|
|
|
|
/**
|
|
* Unescape an escaped string.
|
|
* <ul>
|
|
* <li>'+' characters are replaced by
|
|
* ' ' characters.
|
|
* <li>Valid "%xx" escape sequences are replaced by the
|
|
* corresponding unescaped character.
|
|
* <li>Invalid escape sequences such as %1z", are passed through unchanged.
|
|
* <ol>
|
|
* @param string the escaped string
|
|
* @return the unescaped string.
|
|
*/
|
|
public String unescape(String string) {
|
|
// Early exit if no escaped characters.
|
|
int firstEscape = string.indexOf('%');
|
|
if ( firstEscape < 0) {
|
|
firstEscape = string.indexOf('+');
|
|
if (firstEscape < 0) {
|
|
return string;
|
|
}
|
|
}
|
|
|
|
int length = string.length();
|
|
|
|
StringBuilder stringBuilder = new StringBuilder(length);
|
|
stringBuilder.append(string.substring(0, firstEscape));
|
|
for (int i = firstEscape; i < length; i++) {
|
|
char c = string.charAt(i);
|
|
if (c == '+') {
|
|
c = ' ';
|
|
}
|
|
else if ( c == '%' && i + 2 < length) {
|
|
char c1 = string.charAt(i + 1);
|
|
char c2 = string.charAt(i + 2);
|
|
if (isHexDigit(c1) && isHexDigit(c2)) {
|
|
c = (char) (decodeHexDigit(c1) * 16 + decodeHexDigit(c2));
|
|
i += 2;
|
|
}
|
|
}
|
|
stringBuilder.append(c);
|
|
}
|
|
return stringBuilder.toString();
|
|
}
|
|
|
|
/**
|
|
* Test if a character is a hexidecimal digit. Both upper case and lower
|
|
* case hex digits are allowed.
|
|
* @param c the character to test
|
|
* @return true if c is a hex digit.
|
|
*/
|
|
protected boolean isHexDigit(char c) {
|
|
return decodeHexDigit(c) >= 0;
|
|
}
|
|
|
|
/**
|
|
* Convert a character that represents a hexidecimal digit into an integer.
|
|
* If the character is not a hexidecimal digit, then -1 is returned.
|
|
* Both upper case and lower case hex digits are allowed.
|
|
* @param c the hexidecimal digit.
|
|
* @return the integer value of the hexidecimal digit.
|
|
*/
|
|
|
|
protected int decodeHexDigit(char c) {
|
|
if (c >= '0' && c <= '9') {
|
|
return c - '0';
|
|
}
|
|
else if (c >= 'A' && c <= 'F') {
|
|
return c - 'A' + 10;
|
|
}
|
|
else if (c >= 'a' && c <= 'f') {
|
|
return c - 'a' + 10;
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear the existing entries. Called to get ready to parse a new
|
|
* query string.
|
|
*/
|
|
protected void clear() {
|
|
mEntries.clear();
|
|
mEntriesList.clear();
|
|
}
|
|
}
|
|
|