1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNotSame; 23 import static org.junit.Assert.assertNull; 24 import static org.junit.Assert.assertTrue; 25 26 import android.net.UrlQuerySanitizer; 27 import android.net.UrlQuerySanitizer.IllegalCharacterValueSanitizer; 28 import android.net.UrlQuerySanitizer.ParameterValuePair; 29 import android.net.UrlQuerySanitizer.ValueSanitizer; 30 import android.os.Build; 31 32 import androidx.test.ext.junit.runners.AndroidJUnit4; 33 import androidx.test.filters.SmallTest; 34 35 import com.android.testutils.DevSdkIgnoreRule; 36 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; 37 38 import org.junit.Rule; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 42 import java.util.List; 43 import java.util.Set; 44 45 @SmallTest 46 @RunWith(AndroidJUnit4.class) 47 public class UrlQuerySanitizerTest { 48 @Rule 49 public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); 50 51 private static final int ALL_OK = IllegalCharacterValueSanitizer.ALL_OK; 52 53 // URL for test. 54 private static final String TEST_URL = "http://example.com/?name=Joe+User&age=20&height=175"; 55 56 // Default sanitizer's change when "+". 57 private static final String EXPECTED_UNDERLINE_NAME = "Joe_User"; 58 59 // IllegalCharacterValueSanitizer sanitizer's change when "+". 60 private static final String EXPECTED_SPACE_NAME = "Joe User"; 61 private static final String EXPECTED_AGE = "20"; 62 private static final String EXPECTED_HEIGHT = "175"; 63 private static final String NAME = "name"; 64 private static final String AGE = "age"; 65 private static final String HEIGHT = "height"; 66 67 @Test testUrlQuerySanitizer()68 public void testUrlQuerySanitizer() { 69 MockUrlQuerySanitizer uqs = new MockUrlQuerySanitizer(); 70 assertFalse(uqs.getAllowUnregisteredParamaters()); 71 72 final String query = "book=thinking in java&price=108"; 73 final String book = "book"; 74 final String bookName = "thinking in java"; 75 final String price = "price"; 76 final String bookPrice = "108"; 77 final String notExistPar = "notExistParameter"; 78 uqs.registerParameters(new String[]{book, price}, UrlQuerySanitizer.getSpaceLegal()); 79 uqs.parseQuery(query); 80 assertTrue(uqs.hasParameter(book)); 81 assertTrue(uqs.hasParameter(price)); 82 assertFalse(uqs.hasParameter(notExistPar)); 83 assertEquals(bookName, uqs.getValue(book)); 84 assertEquals(bookPrice, uqs.getValue(price)); 85 assertNull(uqs.getValue(notExistPar)); 86 uqs.clear(); 87 assertFalse(uqs.hasParameter(book)); 88 assertFalse(uqs.hasParameter(price)); 89 90 uqs.parseEntry(book, bookName); 91 assertTrue(uqs.hasParameter(book)); 92 assertEquals(bookName, uqs.getValue(book)); 93 uqs.parseEntry(price, bookPrice); 94 assertTrue(uqs.hasParameter(price)); 95 assertEquals(bookPrice, uqs.getValue(price)); 96 assertFalse(uqs.hasParameter(notExistPar)); 97 assertNull(uqs.getValue(notExistPar)); 98 99 uqs = new MockUrlQuerySanitizer(TEST_URL); 100 assertTrue(uqs.getAllowUnregisteredParamaters()); 101 102 assertTrue(uqs.hasParameter(NAME)); 103 assertTrue(uqs.hasParameter(AGE)); 104 assertTrue(uqs.hasParameter(HEIGHT)); 105 assertFalse(uqs.hasParameter(notExistPar)); 106 107 assertEquals(EXPECTED_UNDERLINE_NAME, uqs.getValue(NAME)); 108 assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); 109 assertEquals(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); 110 assertNull(uqs.getValue(notExistPar)); 111 112 final int ContainerLen = 3; 113 Set<String> urlSet = uqs.getParameterSet(); 114 assertEquals(ContainerLen, urlSet.size()); 115 assertTrue(urlSet.contains(NAME)); 116 assertTrue(urlSet.contains(AGE)); 117 assertTrue(urlSet.contains(HEIGHT)); 118 assertFalse(urlSet.contains(notExistPar)); 119 120 List<ParameterValuePair> urlList = uqs.getParameterList(); 121 assertEquals(ContainerLen, urlList.size()); 122 ParameterValuePair pvp = urlList.get(0); 123 assertEquals(NAME, pvp.mParameter); 124 assertEquals(EXPECTED_UNDERLINE_NAME, pvp.mValue); 125 pvp = urlList.get(1); 126 assertEquals(AGE, pvp.mParameter); 127 assertEquals(EXPECTED_AGE, pvp.mValue); 128 pvp = urlList.get(2); 129 assertEquals(HEIGHT, pvp.mParameter); 130 assertEquals(EXPECTED_HEIGHT, pvp.mValue); 131 132 assertFalse(uqs.getPreferFirstRepeatedParameter()); 133 uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT + 1); 134 assertEquals(ContainerLen, urlSet.size()); 135 assertEquals(ContainerLen + 1, urlList.size()); 136 assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); 137 138 uqs.setPreferFirstRepeatedParameter(true); 139 assertTrue(uqs.getPreferFirstRepeatedParameter()); 140 uqs.addSanitizedEntry(HEIGHT, EXPECTED_HEIGHT); 141 assertEquals(ContainerLen, urlSet.size()); 142 assertEquals(ContainerLen + 2, urlList.size()); 143 assertEquals(EXPECTED_HEIGHT + 1, uqs.getValue(HEIGHT)); 144 145 uqs.registerParameter(NAME, null); 146 assertNull(uqs.getValueSanitizer(NAME)); 147 assertNotNull(uqs.getEffectiveValueSanitizer(NAME)); 148 149 uqs.setAllowUnregisteredParamaters(false); 150 assertFalse(uqs.getAllowUnregisteredParamaters()); 151 uqs.registerParameter(NAME, null); 152 assertNull(uqs.getEffectiveValueSanitizer(NAME)); 153 154 ValueSanitizer vs = new IllegalCharacterValueSanitizer(ALL_OK); 155 uqs.registerParameter(NAME, vs); 156 uqs.parseUrl(TEST_URL); 157 assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); 158 assertNotSame(EXPECTED_AGE, uqs.getValue(AGE)); 159 160 String[] register = {NAME, AGE}; 161 uqs.registerParameters(register, vs); 162 uqs.parseUrl(TEST_URL); 163 assertEquals(EXPECTED_SPACE_NAME, uqs.getValue(NAME)); 164 assertEquals(EXPECTED_AGE, uqs.getValue(AGE)); 165 assertNotSame(EXPECTED_HEIGHT, uqs.getValue(HEIGHT)); 166 167 uqs.setUnregisteredParameterValueSanitizer(vs); 168 assertEquals(vs, uqs.getUnregisteredParameterValueSanitizer()); 169 170 vs = UrlQuerySanitizer.getAllIllegal(); 171 assertEquals("Joe_User", vs.sanitize("Joe<User")); 172 vs = UrlQuerySanitizer.getAllButNulAndAngleBracketsLegal(); 173 assertEquals("Joe User", vs.sanitize("Joe<>\0User")); 174 vs = UrlQuerySanitizer.getAllButNulLegal(); 175 assertEquals("Joe User", vs.sanitize("Joe\0User")); 176 vs = UrlQuerySanitizer.getAllButWhitespaceLegal(); 177 assertEquals("Joe_User", vs.sanitize("Joe User")); 178 vs = UrlQuerySanitizer.getAmpAndSpaceLegal(); 179 assertEquals("Joe User&", vs.sanitize("Joe User&")); 180 vs = UrlQuerySanitizer.getAmpLegal(); 181 assertEquals("Joe_User&", vs.sanitize("Joe User&")); 182 vs = UrlQuerySanitizer.getSpaceLegal(); 183 assertEquals("Joe User ", vs.sanitize("Joe User&")); 184 vs = UrlQuerySanitizer.getUrlAndSpaceLegal(); 185 assertEquals("Joe User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); 186 vs = UrlQuerySanitizer.getUrlLegal(); 187 assertEquals("Joe_User&Smith%B5'\'", vs.sanitize("Joe User&Smith%B5'\'")); 188 189 String escape = "Joe"; 190 assertEquals(escape, uqs.unescape(escape)); 191 String expectedPlus = "Joe User"; 192 String expectedPercentSignHex = "title=" + Character.toString((char)181); 193 String initialPlus = "Joe+User"; 194 String initialPercentSign = "title=%B5"; 195 assertEquals(expectedPlus, uqs.unescape(initialPlus)); 196 assertEquals(expectedPercentSignHex, uqs.unescape(initialPercentSign)); 197 String expectedPlusThenPercentSign = "Joe Random, User"; 198 String plusThenPercentSign = "Joe+Random%2C%20User"; 199 assertEquals(expectedPlusThenPercentSign, uqs.unescape(plusThenPercentSign)); 200 String expectedPercentSignThenPlus = "Joe, Random User"; 201 String percentSignThenPlus = "Joe%2C+Random+User"; 202 assertEquals(expectedPercentSignThenPlus, uqs.unescape(percentSignThenPlus)); 203 204 assertTrue(uqs.decodeHexDigit('0') >= 0); 205 assertTrue(uqs.decodeHexDigit('b') >= 0); 206 assertTrue(uqs.decodeHexDigit('F') >= 0); 207 assertTrue(uqs.decodeHexDigit('$') < 0); 208 209 assertTrue(uqs.isHexDigit('0')); 210 assertTrue(uqs.isHexDigit('b')); 211 assertTrue(uqs.isHexDigit('F')); 212 assertFalse(uqs.isHexDigit('$')); 213 214 uqs.clear(); 215 assertEquals(0, urlSet.size()); 216 assertEquals(0, urlList.size()); 217 218 uqs.setPreferFirstRepeatedParameter(true); 219 assertTrue(uqs.getPreferFirstRepeatedParameter()); 220 uqs.setPreferFirstRepeatedParameter(false); 221 assertFalse(uqs.getPreferFirstRepeatedParameter()); 222 223 UrlQuerySanitizer uq = new UrlQuerySanitizer(); 224 uq.setPreferFirstRepeatedParameter(true); 225 final String PARA_ANSWER = "answer"; 226 uq.registerParameter(PARA_ANSWER, new MockValueSanitizer()); 227 uq.parseUrl("http://www.google.com/question?answer=13&answer=42"); 228 assertEquals("13", uq.getValue(PARA_ANSWER)); 229 230 uq.setPreferFirstRepeatedParameter(false); 231 uq.parseQuery("http://www.google.com/question?answer=13&answer=42"); 232 assertEquals("42", uq.getValue(PARA_ANSWER)); 233 234 } 235 236 @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // Only fixed in R 237 public void testScriptUrlOk_73822755() { 238 ValueSanitizer sanitizer = new UrlQuerySanitizer.IllegalCharacterValueSanitizer( 239 UrlQuerySanitizer.IllegalCharacterValueSanitizer.SCRIPT_URL_OK); 240 assertEquals("javascript:alert()", sanitizer.sanitize("javascript:alert()")); 241 } 242 243 @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // Only fixed in R 244 public void testScriptUrlBlocked_73822755() { 245 ValueSanitizer sanitizer = UrlQuerySanitizer.getUrlAndSpaceLegal(); 246 assertEquals("", sanitizer.sanitize("javascript:alert()")); 247 } 248 249 private static class MockValueSanitizer implements ValueSanitizer{ 250 251 public String sanitize(String value) { 252 return value; 253 } 254 } 255 256 class MockUrlQuerySanitizer extends UrlQuerySanitizer { 257 public MockUrlQuerySanitizer() { 258 super(); 259 } 260 261 public MockUrlQuerySanitizer(String url) { 262 super(url); 263 } 264 265 @Override 266 protected void addSanitizedEntry(String parameter, String value) { 267 super.addSanitizedEntry(parameter, value); 268 } 269 270 @Override 271 protected void clear() { 272 super.clear(); 273 } 274 275 @Override 276 protected int decodeHexDigit(char c) { 277 return super.decodeHexDigit(c); 278 } 279 280 @Override 281 protected boolean isHexDigit(char c) { 282 return super.isHexDigit(c); 283 } 284 285 @Override 286 protected void parseEntry(String parameter, String value) { 287 super.parseEntry(parameter, value); 288 } 289 } 290 } 291