19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.net;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
22cb64d430627b71221c588ef5f23599dd34a89ee9Elliott Hughesimport java.util.Locale;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Set;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.StringTokenizer;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sanitizes the Query portion of a URL. Simple example:
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sanitizer.setAllowUnregisteredParamaters(true);
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sanitizer.parseUrl("http://example.com/?name=Joe+User");
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * String name = sanitizer.getValue("name"));
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // name now contains "Joe_User"
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </code>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Register ValueSanitizers to customize the way individual
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * parameters are sanitized:
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sanitizer.registerParamater("name", UrlQuerySanitizer.createSpaceLegal());
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sanitizer.parseUrl("http://example.com/?name=Joe+User");
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * String name = sanitizer.getValue("name"));
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // name now contains "Joe User". (The string is first decoded, which
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // converts the '+' to a ' '. Then the string is sanitized, which
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // converts the ' ' to an '_'. (The ' ' is converted because the default
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * unregistered parameter sanitizer does not allow any special characters,
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and ' ' is a special character.)
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </code>
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * There are several ways to create ValueSanitizers. In order of increasing
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sophistication:
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <ol>
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li>Call one of the UrlQuerySanitizer.createXXX() methods.
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li>Construct your own instance of
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UrlQuerySanitizer.IllegalCharacterValueSanitizer.
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li>Subclass UrlQuerySanitizer.ValueSanitizer to define your own value
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sanitizer.
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </ol>
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class UrlQuerySanitizer {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A simple tuple that holds parameter-value pairs.
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class ParameterValuePair {
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Construct a parameter-value tuple.
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param parameter an unencoded parameter
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param value an unencoded value
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ParameterValuePair(String parameter,
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String value) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mParameter = parameter;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mValue = value;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The unencoded parameter
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String mParameter;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The unencoded value
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String mValue;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final private HashMap<String, ValueSanitizer> mSanitizers =
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new HashMap<String, ValueSanitizer>();
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final private HashMap<String, String> mEntries =
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new HashMap<String, String>();
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final private ArrayList<ParameterValuePair> mEntriesList =
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new ArrayList<ParameterValuePair>();
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAllowUnregisteredParamaters;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mPreferFirstRepeatedParameter;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ValueSanitizer mUnregisteredParameterValueSanitizer =
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        getAllIllegal();
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A functor used to sanitize a single query value.
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static interface ValueSanitizer {
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Sanitize an unencoded value.
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param value
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return the sanitized unencoded value
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String sanitize(String value);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sanitize values based on which characters they contain. Illegal
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * characters are replaced with either space or '_', depending upon
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * whether space is a legal character or not.
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static class IllegalCharacterValueSanitizer implements
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ValueSanitizer {
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mFlags;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow space (' ') characters.
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int SPACE_OK =              1 << 0;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow whitespace characters other than space. The
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * other whitespace characters are
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * '\t' '\f' '\n' '\r' and '\0x000b' (vertical tab)
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int OTHER_WHITESPACE_OK =  1 << 1;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow characters with character codes 128 to 255.
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int NON_7_BIT_ASCII_OK =    1 << 2;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow double quote characters. ('"')
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int DQUOTE_OK =             1 << 3;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow single quote characters. ('\'')
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int SQUOTE_OK =             1 << 4;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow less-than characters. ('<')
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int LT_OK =                 1 << 5;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow greater-than characters. ('>')
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int GT_OK =                 1 << 6;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow ampersand characters ('&')
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int AMP_OK =                1 << 7;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow percent-sign characters ('%')
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int PCT_OK =                1 << 8;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow nul characters ('\0')
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int NUL_OK =                1 << 9;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Allow text to start with a script URL
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * such as "javascript:" or "vbscript:"
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int SCRIPT_URL_OK =         1 << 10;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Mask with all fields set to OK
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int ALL_OK =                0x7ff;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Mask with both regular space and other whitespace OK
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int ALL_WHITESPACE_OK =
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SPACE_OK | OTHER_WHITESPACE_OK;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Common flag combinations:
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Deny all special characters.
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Deny script URLs.
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int ALL_ILLEGAL =
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            0;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow all special characters except Nul. ('\0').
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow script URLs.
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int ALL_BUT_NUL_LEGAL =
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ALL_OK & ~NUL_OK;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow all special characters except for:
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  <li>whitespace characters
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  <li>Nul ('\0')
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow script URLs.
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int ALL_BUT_WHITESPACE_LEGAL =
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ALL_OK & ~(ALL_WHITESPACE_OK | NUL_OK);
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow characters used by encoded URLs.
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Deny script URLs.
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int URL_LEGAL =
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            NON_7_BIT_ASCII_OK | SQUOTE_OK | AMP_OK | PCT_OK;
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow characters used by encoded URLs.
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow spaces.
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Deny script URLs.
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int URL_AND_SPACE_LEGAL =
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            URL_LEGAL | SPACE_OK;
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow ampersand.
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Deny script URLs.
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int AMP_LEGAL =
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            AMP_OK;
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow ampersand.
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow space.
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Deny script URLs.
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int AMP_AND_SPACE_LEGAL =
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            AMP_OK | SPACE_OK;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow space.
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Deny script URLs.
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int SPACE_LEGAL =
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SPACE_OK;
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Allow all but.
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ul>
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  <li>Nul ('\0')
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  <li>Angle brackets ('<', '>')
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>Deny script URLs.
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ul>
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final static int ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL =
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ALL_OK & ~(NUL_OK | LT_OK | GT_OK);
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *  Script URL definitions
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final static String JAVASCRIPT_PREFIX = "javascript:";
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final static String VBSCRIPT_PREFIX = "vbscript:";
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final static int MIN_SCRIPT_PREFIX_LENGTH = Math.min(
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                JAVASCRIPT_PREFIX.length(), VBSCRIPT_PREFIX.length());
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Construct a sanitizer. The parameters set the behavior of the
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * sanitizer.
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param flags some combination of the XXX_OK flags.
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public IllegalCharacterValueSanitizer(
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int flags) {
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFlags = flags;
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Sanitize a value.
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <ol>
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>If script URLs are not OK, the will be removed.
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li>If neither spaces nor other white space is OK, then
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * white space will be trimmed from the beginning and end of
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the URL. (Just the actual white space characters are trimmed, not
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * other control codes.)
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <li> Illegal characters will be replaced with
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * either ' ' or '_', depending on whether a space is itself a
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * legal character.
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * </ol>
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param value
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return the sanitized value
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String sanitize(String value) {
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (value == null) {
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int length = value.length();
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((mFlags & SCRIPT_URL_OK) != 0) {
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (length >= MIN_SCRIPT_PREFIX_LENGTH) {
309cb64d430627b71221c588ef5f23599dd34a89ee9Elliott Hughes                    String asLower = value.toLowerCase(Locale.ROOT);
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (asLower.startsWith(JAVASCRIPT_PREFIX)  ||
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        asLower.startsWith(VBSCRIPT_PREFIX)) {
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return "";
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If whitespace isn't OK, get rid of whitespace at beginning
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // and end of value.
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ( (mFlags & ALL_WHITESPACE_OK) == 0) {
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                value = trimWhitespace(value);
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // The length could have changed, so we need to correct
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // the length variable.
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                length = value.length();
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            StringBuilder stringBuilder = new StringBuilder(length);
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for(int i = 0; i < length; i++) {
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                char c = value.charAt(i);
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!characterIsLegal(c)) {
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if ((mFlags & SPACE_OK) != 0) {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        c = ' ';
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    else {
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        c = '_';
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                stringBuilder.append(c);
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return stringBuilder.toString();
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Trim whitespace from the beginning and end of a string.
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Note: can't use {@link String#trim} because {@link String#trim} has a
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * different definition of whitespace than we want.
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param value the string to trim
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return the trimmed string
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String trimWhitespace(String value) {
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int start = 0;
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int last = value.length() - 1;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int end = last;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (start <= end && isWhitespace(value.charAt(start))) {
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                start++;
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (end >= start && isWhitespace(value.charAt(end))) {
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                end--;
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (start == 0 && end == last) {
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return value;
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return value.substring(start, end + 1);
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Check if c is whitespace.
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param c character to test
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if c is a whitespace character
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private boolean isWhitespace(char c) {
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch(c) {
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case ' ':
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '\t':
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '\f':
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '\n':
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '\r':
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case 11: /* VT */
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Check whether an individual character is legal. Uses the
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * flag bit-set passed into the constructor.
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param c
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if c is a legal character
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private boolean characterIsLegal(char c) {
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch(c) {
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case ' ' : return (mFlags & SPACE_OK) != 0;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '\t': case '\f': case '\n': case '\r': case 11: /* VT */
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project              return (mFlags & OTHER_WHITESPACE_OK) != 0;
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '\"': return (mFlags & DQUOTE_OK) != 0;
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '\'': return (mFlags & SQUOTE_OK) != 0;
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '<' : return (mFlags & LT_OK) != 0;
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '>' : return (mFlags & GT_OK) != 0;
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '&' : return (mFlags & AMP_OK) != 0;
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '%' : return (mFlags & PCT_OK) != 0;
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case '\0': return (mFlags & NUL_OK) != 0;
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default  : return (c >= 32 && c < 127) ||
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ((c >= 128) && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the current value sanitizer used when processing
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * unregistered parameter values.
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <b>Note:</b> The default unregistered parameter value sanitizer is
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * one that doesn't allow any special characters, similar to what
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is returned by calling createAllIllegal.
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the current ValueSanitizer used to sanitize unregistered
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * parameter values.
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ValueSanitizer getUnregisteredParameterValueSanitizer() {
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mUnregisteredParameterValueSanitizer;
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the value sanitizer used when processing unregistered
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * parameter values.
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param sanitizer set the ValueSanitizer used to sanitize unregistered
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * parameter values.
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setUnregisteredParameterValueSanitizer(
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ValueSanitizer sanitizer) {
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mUnregisteredParameterValueSanitizer = sanitizer;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Private fields for singleton sanitizers:
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ValueSanitizer sAllIllegal =
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new IllegalCharacterValueSanitizer(
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IllegalCharacterValueSanitizer.ALL_ILLEGAL);
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ValueSanitizer sAllButNulLegal =
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new IllegalCharacterValueSanitizer(
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IllegalCharacterValueSanitizer.ALL_BUT_NUL_LEGAL);
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ValueSanitizer sAllButWhitespaceLegal =
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new IllegalCharacterValueSanitizer(
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IllegalCharacterValueSanitizer.ALL_BUT_WHITESPACE_LEGAL);
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ValueSanitizer sURLLegal =
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new IllegalCharacterValueSanitizer(
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IllegalCharacterValueSanitizer.URL_LEGAL);
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ValueSanitizer sUrlAndSpaceLegal =
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new IllegalCharacterValueSanitizer(
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IllegalCharacterValueSanitizer.URL_AND_SPACE_LEGAL);
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ValueSanitizer sAmpLegal =
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new IllegalCharacterValueSanitizer(
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IllegalCharacterValueSanitizer.AMP_LEGAL);
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ValueSanitizer sAmpAndSpaceLegal =
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new IllegalCharacterValueSanitizer(
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IllegalCharacterValueSanitizer.AMP_AND_SPACE_LEGAL);
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ValueSanitizer sSpaceLegal =
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new IllegalCharacterValueSanitizer(
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IllegalCharacterValueSanitizer.SPACE_LEGAL);
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final ValueSanitizer sAllButNulAndAngleBracketsLegal =
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new IllegalCharacterValueSanitizer(
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IllegalCharacterValueSanitizer.ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a value sanitizer that does not allow any special characters,
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and also does not allow script URLs.
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a value sanitizer
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final ValueSanitizer getAllIllegal() {
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sAllIllegal;
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a value sanitizer that allows everything except Nul ('\0')
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * characters. Script URLs are allowed.
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a value sanitizer
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final ValueSanitizer getAllButNulLegal() {
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sAllButNulLegal;
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a value sanitizer that allows everything except Nul ('\0')
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * characters, space (' '), and other whitespace characters.
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Script URLs are allowed.
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a value sanitizer
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final ValueSanitizer getAllButWhitespaceLegal() {
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sAllButWhitespaceLegal;
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a value sanitizer that allows all the characters used by
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * encoded URLs. Does not allow script URLs.
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a value sanitizer
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final ValueSanitizer getUrlLegal() {
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sURLLegal;
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a value sanitizer that allows all the characters used by
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * encoded URLs and allows spaces, which are not technically legal
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in encoded URLs, but commonly appear anyway.
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Does not allow script URLs.
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a value sanitizer
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final ValueSanitizer getUrlAndSpaceLegal() {
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sUrlAndSpaceLegal;
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a value sanitizer that does not allow any special characters
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * except ampersand ('&'). Does not allow script URLs.
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a value sanitizer
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final ValueSanitizer getAmpLegal() {
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sAmpLegal;
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a value sanitizer that does not allow any special characters
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * except ampersand ('&') and space (' '). Does not allow script URLs.
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a value sanitizer
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final ValueSanitizer getAmpAndSpaceLegal() {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sAmpAndSpaceLegal;
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a value sanitizer that does not allow any special characters
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * except space (' '). Does not allow script URLs.
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a value sanitizer
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final ValueSanitizer getSpaceLegal() {
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sSpaceLegal;
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a value sanitizer that allows any special characters
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * except angle brackets ('<' and '>') and Nul ('\0').
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Allows script URLs.
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a value sanitizer
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final ValueSanitizer getAllButNulAndAngleBracketsLegal() {
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sAllButNulAndAngleBracketsLegal;
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructs a UrlQuerySanitizer.
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Defaults:
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <ul>
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li>unregistered parameters are not allowed.
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li>the last instance of a repeated parameter is preferred.
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li>The default value sanitizer is an AllIllegal value sanitizer.
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <ul>
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public UrlQuerySanitizer() {
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructs a UrlQuerySanitizer and parse a URL.
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This constructor is provided for convenience when the
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * default parsing behavior is acceptable.
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Because the URL is parsed before the constructor returns, there isn't
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a chance to configure the sanitizer to change the parsing behavior.
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <code>
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * UrlQuerySanitizer sanitizer = new UrlQuerySanitizer(myUrl);
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * String name = sanitizer.getValue("name");
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * </code>
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Defaults:
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <ul>
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li>unregistered parameters <em>are</em> allowed.
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li>the last instance of a repeated parameter is preferred.
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li>The default value sanitizer is an AllIllegal value sanitizer.
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <ul>
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public UrlQuerySanitizer(String url) {
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setAllowUnregisteredParamaters(true);
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        parseUrl(url);
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Parse the query parameters out of an encoded URL.
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Works by extracting the query portion from the URL and then
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * calling parseQuery(). If there is no query portion it is
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * treated as if the query portion is an empty string.
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param url the encoded URL to parse.
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void parseUrl(String url) {
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int queryIndex = url.indexOf('?');
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String query;
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (queryIndex >= 0) {
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            query = url.substring(queryIndex + 1);
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else {
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            query = "";
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        parseQuery(query);
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Parse a query. A query string is any number of parameter-value clauses
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * separated by any non-zero number of ampersands. A parameter-value clause
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is a parameter followed by an equal sign, followed by a value. If the
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * equal sign is missing, the value is assumed to be the empty string.
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param query the query to parse.
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void parseQuery(String query) {
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        clear();
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Split by '&'
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringTokenizer tokenizer = new StringTokenizer(query, "&");
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while(tokenizer.hasMoreElements()) {
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String attributeValuePair = tokenizer.nextToken();
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attributeValuePair.length() > 0) {
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int assignmentIndex = attributeValuePair.indexOf('=');
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (assignmentIndex < 0) {
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // No assignment found, treat as if empty value
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    parseEntry(attributeValuePair, "");
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                else {
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    parseEntry(attributeValuePair.substring(0, assignmentIndex),
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            attributeValuePair.substring(assignmentIndex + 1));
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get a set of all of the parameters found in the sanitized query.
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: Do not modify this set. Treat it as a read-only set.
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return all the parameters found in the current query.
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Set<String> getParameterSet() {
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mEntries.keySet();
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * An array list of all of the parameter value pairs in the sanitized
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * query, in the order they appeared in the query. May contain duplicate
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * parameters.
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p class="note"><b>Note:</b> Do not modify this list. Treat it as a read-only list.</p>
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<ParameterValuePair> getParameterList() {
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mEntriesList;
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Check if a parameter exists in the current sanitized query.
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parameter the unencoded name of a parameter.
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the paramater exists in the current sanitized queary.
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean hasParameter(String parameter) {
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mEntries.containsKey(parameter);
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the value for a parameter in the current sanitized query.
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if the parameter does not
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * exit.
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parameter the unencoded name of a parameter.
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the sanitized unencoded value of the parameter,
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * or null if the parameter does not exist.
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String getValue(String parameter) {
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mEntries.get(parameter);
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Register a value sanitizer for a particular parameter. Can also be used
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to replace or remove an already-set value sanitizer.
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Registering a non-null value sanitizer for a particular parameter
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * makes that parameter a registered parameter.
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parameter an unencoded parameter name
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param valueSanitizer the value sanitizer to use for a particular
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * parameter. May be null in order to unregister that parameter.
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getAllowUnregisteredParamaters()
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void registerParameter(String parameter,
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ValueSanitizer valueSanitizer) {
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (valueSanitizer == null) {
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSanitizers.remove(parameter);
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSanitizers.put(parameter, valueSanitizer);
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Register a value sanitizer for an array of parameters.
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parameters An array of unencoded parameter names.
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param valueSanitizer
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #registerParameter
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void registerParameters(String[] parameters,
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ValueSanitizer valueSanitizer) {
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int length = parameters.length;
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for(int i = 0; i < length; i++) {
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSanitizers.put(parameters[i], valueSanitizer);
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set whether or not unregistered parameters are allowed. If they
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * are not allowed, then they will be dropped when a query is sanitized.
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Defaults to false.
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param allowUnregisteredParamaters true to allow unregistered parameters.
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getAllowUnregisteredParamaters()
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAllowUnregisteredParamaters(
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean allowUnregisteredParamaters) {
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAllowUnregisteredParamaters = allowUnregisteredParamaters;
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get whether or not unregistered parameters are allowed. If not
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * allowed, they will be dropped when a query is parsed.
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if unregistered parameters are allowed.
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setAllowUnregisteredParamaters(boolean)
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean getAllowUnregisteredParamaters() {
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAllowUnregisteredParamaters;
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set whether or not the first occurrence of a repeated parameter is
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * preferred. True means the first repeated parameter is preferred.
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * False means that the last repeated parameter is preferred.
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The preferred parameter is the one that is returned when getParameter
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is called.
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * defaults to false.
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param preferFirstRepeatedParameter True if the first repeated
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * parameter is preferred.
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getPreferFirstRepeatedParameter()
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setPreferFirstRepeatedParameter(
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean preferFirstRepeatedParameter) {
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPreferFirstRepeatedParameter = preferFirstRepeatedParameter;
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get whether or not the first occurrence of a repeated parameter is
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * preferred.
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the first occurrence of a repeated parameter is
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * preferred.
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setPreferFirstRepeatedParameter(boolean)
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean getPreferFirstRepeatedParameter() {
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mPreferFirstRepeatedParameter;
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Parse an escaped parameter-value pair. The default implementation
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * unescapes both the parameter and the value, then looks up the
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * effective value sanitizer for the parameter and uses it to sanitize
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the value. If all goes well then addSanitizedValue is called with
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the unescaped parameter and the sanitized unescaped value.
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parameter an escaped parameter
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param value an unsanitzied escaped value
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void parseEntry(String parameter, String value) {
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String unescapedParameter = unescape(parameter);
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         ValueSanitizer valueSanitizer =
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            getEffectiveValueSanitizer(unescapedParameter);
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (valueSanitizer == null) {
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String unescapedValue = unescape(value);
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String sanitizedValue = valueSanitizer.sanitize(unescapedValue);
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        addSanitizedEntry(unescapedParameter, sanitizedValue);
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Record a sanitized parameter-value pair. Override if you want to
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * do additional filtering or validation.
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parameter an unescaped parameter
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param value a sanitized unescaped value
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void addSanitizedEntry(String parameter, String value) {
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEntriesList.add(
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new ParameterValuePair(parameter, value));
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mPreferFirstRepeatedParameter) {
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mEntries.containsKey(parameter)) {
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEntries.put(parameter, value);
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the value sanitizer for a parameter. Returns null if there
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is no value sanitizer registered for the parameter.
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parameter the unescaped parameter
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the currently registered value sanitizer for this parameter.
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #registerParameter(String, android.net.UrlQuerySanitizer.ValueSanitizer)
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ValueSanitizer getValueSanitizer(String parameter) {
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mSanitizers.get(parameter);
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the effective value sanitizer for a parameter. Like getValueSanitizer,
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * except if there is no value sanitizer registered for a parameter, and
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * unregistered paramaters are allowed, then the default value sanitizer is
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * returned.
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parameter an unescaped parameter
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the effective value sanitizer for a parameter.
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ValueSanitizer getEffectiveValueSanitizer(String parameter) {
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ValueSanitizer sanitizer = getValueSanitizer(parameter);
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (sanitizer == null && mAllowUnregisteredParamaters) {
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sanitizer = getUnregisteredParameterValueSanitizer();
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return sanitizer;
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Unescape an escaped string.
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <ul>
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li>'+' characters are replaced by
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * ' ' characters.
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li>Valid "%xx" escape sequences are replaced by the
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * corresponding unescaped character.
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li>Invalid escape sequences such as %1z", are passed through unchanged.
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <ol>
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param string the escaped string
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the unescaped string.
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String unescape(String string) {
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Early exit if no escaped characters.
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int firstEscape = string.indexOf('%');
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ( firstEscape < 0) {
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            firstEscape = string.indexOf('+');
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (firstEscape < 0) {
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return string;
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int length = string.length();
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder stringBuilder = new StringBuilder(length);
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        stringBuilder.append(string.substring(0, firstEscape));
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = firstEscape; i < length; i++) {
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = string.charAt(i);
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c == '+') {
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c = ' ';
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else if ( c == '%' && i + 2 < length) {
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                char c1 = string.charAt(i + 1);
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                char c2 = string.charAt(i + 2);
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isHexDigit(c1) && isHexDigit(c2)) {
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    c = (char) (decodeHexDigit(c1) * 16 + decodeHexDigit(c2));
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    i += 2;
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            stringBuilder.append(c);
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return stringBuilder.toString();
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Test if a character is a hexidecimal digit. Both upper case and lower
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * case hex digits are allowed.
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param c the character to test
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if c is a hex digit.
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean isHexDigit(char c) {
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return decodeHexDigit(c) >= 0;
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Convert a character that represents a hexidecimal digit into an integer.
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If the character is not a hexidecimal digit, then -1 is returned.
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Both upper case and lower case hex digits are allowed.
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param c the hexidecimal digit.
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the integer value of the hexidecimal digit.
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected int decodeHexDigit(char c) {
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '0' && c <= '9') {
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return c - '0';
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else if (c >= 'A' && c <= 'F') {
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return c - 'A' + 10;
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else if (c >= 'a' && c <= 'f') {
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return c - 'a' + 10;
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else {
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Clear the existing entries. Called to get ready to parse a new
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * query string.
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void clear() {
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEntries.clear();
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEntriesList.clear();
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
915