1/* 2 * Copyright (C) 2011 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 17package libcore.java.net; 18 19import java.io.UnsupportedEncodingException; 20import java.net.URI; 21import java.net.URISyntaxException; 22import java.net.URLDecoder; 23import java.net.URLEncoder; 24import java.nio.charset.IllegalCharsetNameException; 25import java.nio.charset.UnsupportedCharsetException; 26import junit.framework.TestCase; 27 28public final class UrlEncodingTest extends TestCase { 29 30 public void testUriRetainsOriginalEncoding() throws Exception { 31 assertEquals("%61", new URI("http://foo#%61").getRawFragment()); 32 } 33 34 /** 35 * URLDecoder and URI disagree on what '+' should decode to. 36 */ 37 public void testDecodingPlus() throws Exception { 38 assertEquals("a b", URLDecoder.decode("a+b")); 39 assertEquals("a b", URLDecoder.decode("a+b", "UTF-8")); 40 assertEquals("a+b", new URI("http://foo#a+b").getFragment()); 41 } 42 43 public void testEncodingPlus() throws Exception { 44 assertEquals("a%2Bb", URLEncoder.encode("a+b")); 45 assertEquals("a%2Bb", URLEncoder.encode("a+b", "UTF-8")); 46 assertEquals("a+b", new URI("http", "foo", "/", "a+b").getRawFragment()); 47 } 48 49 public void testDecodingSpace() throws Exception { 50 assertEquals("a b", URLDecoder.decode("a b")); 51 assertEquals("a b", URLDecoder.decode("a b", "UTF-8")); 52 try { 53 new URI("http://foo#a b"); 54 fail(); 55 } catch (URISyntaxException expected) { 56 } 57 } 58 59 public void testEncodingSpace() throws Exception { 60 assertEquals("a+b", URLEncoder.encode("a b")); 61 assertEquals("a+b", URLEncoder.encode("a b", "UTF-8")); 62 assertEquals("a%20b", new URI("http", "foo", "/", "a b").getRawFragment()); 63 } 64 65 public void testUriDecodingPartial() throws Exception { 66 try { 67 new URI("http://foo#%"); 68 fail(); 69 } catch (URISyntaxException expected) { 70 } 71 try { 72 new URI("http://foo#%0"); 73 fail(); 74 } catch (URISyntaxException expected) { 75 } 76 } 77 78 public void testUrlDecoderDecodingPartial() throws Exception { 79 try { 80 URLDecoder.decode("%"); 81 fail(); 82 } catch (IllegalArgumentException expected) { 83 } 84 try { 85 URLDecoder.decode("%0"); 86 fail(); 87 } catch (IllegalArgumentException expected) { 88 } 89 } 90 91 public void testUriDecodingInvalid() { 92 try { 93 new URI("http://foo#%0g"); 94 fail(); 95 } catch (URISyntaxException expected) { 96 } 97 } 98 99 public void testUrlDecoderDecodingInvalid() { 100 try { 101 URLDecoder.decode("%0g"); 102 fail(); 103 } catch (IllegalArgumentException expected) { 104 } 105 } 106 107 public void testUrlDecoderFailsOnNullCharset() throws Exception { 108 try { 109 URLDecoder.decode("ab", null); 110 fail(); 111 } catch (IllegalCharsetNameException expected) { 112 } catch (NullPointerException expected) { 113 } 114 } 115 116 public void testUrlDecoderFailsOnEmptyCharset() { 117 try { 118 URLDecoder.decode("ab", ""); 119 fail(); 120 } catch (IllegalCharsetNameException expected) { 121 } catch (UnsupportedEncodingException expected) { 122 } 123 } 124 125 public void testUrlEncoderFailsOnNullCharset() throws Exception { 126 try { 127 URLEncoder.encode("ab", null); 128 fail(); 129 } catch (IllegalCharsetNameException expected) { 130 } catch (NullPointerException expected) { 131 } 132 } 133 134 public void testUrlEncoderFailsOnEmptyCharset() { 135 try { 136 URLEncoder.encode("ab", ""); 137 fail(); 138 } catch (IllegalCharsetNameException expected) { 139 } catch (UnsupportedEncodingException expected) { 140 } 141 } 142 143 /** 144 * The RI looks up the charset lazily; Android looks it up eagerly. Either 145 * behavior is acceptable. 146 */ 147 public void testUrlDecoderIgnoresUnnecessaryCharset() throws Exception { 148 try { 149 assertEquals("ab", URLDecoder.decode("ab", "no-such-charset")); 150 // no fail() 151 } catch (UnsupportedCharsetException expected) { 152 } 153 } 154 155 public void testUrlEncoderFailsOnInvalidCharset() throws Exception { 156 try { 157 URLEncoder.encode("ab", "no-such-charset"); 158 fail(); 159 } catch (UnsupportedCharsetException expected) { 160 } catch (UnsupportedEncodingException expected) { 161 } 162 } 163 164 public void testDecoding() throws Exception { 165 assertDecoded("a\u0000b", "a%00b"); 166 assertDecoded("a b", "a%20b"); 167 assertDecoded("a+b", "a%2bb"); 168 assertDecoded("a%b", "a%25b"); 169 assertDecoded("a\u007fb", "a%7fb"); 170 } 171 172 public void testEncoding() throws Exception { 173 assertEncoded("a%25b", "a%b"); 174 assertEncoded("a%7Fb", "a\u007fb"); 175 } 176 177 public void testDecodingLiterals() throws Exception { 178 assertDecoded("\ud842\udf9f", "\ud842\udf9f"); 179 } 180 181 public void testDecodingBrokenUtf8SequenceYieldsReplacementCharacter() throws Exception { 182 assertDecoded("a\ufffdb", "a%ffb"); 183 } 184 185 public void testDecodingBrokenUtf8SequenceYieldsReplacementCharacterSequence() 186 throws Exception { 187 assertDecoded("a%\ufffd%b", "a%25%ff%25b"); 188 } 189 190 public void testDecodingUtf8Octets() throws Exception { 191 assertDecoded("\u20AC", "%e2%82%ac"); 192 assertDecoded("\ud842\udf9f", "%f0%a0%ae%9f"); 193 } 194 195 public void testDecodingNonUsDigits() throws Exception { 196 try { 197 new URI("http://foo#" + "%\u0664\u0661"); 198 fail(); 199 } catch (URISyntaxException expected) { 200 } 201 try { 202 URLDecoder.decode("%\u0664\u0661"); 203 fail(); // RI fails this test returning "A" 204 } catch (IllegalArgumentException expected) { 205 } 206 } 207 208 /** 209 * Android's URLEncoder.encode() failed for surrogate pairs, encoding them 210 * as two replacement characters ("??"). http://b/3436051 211 */ 212 public void testUrlEncoderEncodesNonPrintableNonAsciiCharacters() throws Exception { 213 assertEquals("%00", URLEncoder.encode("\u0000", "UTF-8")); 214 assertEquals("%00", URLEncoder.encode("\u0000")); 215 assertEquals("%E2%82%AC", URLEncoder.encode("\u20AC", "UTF-8")); 216 assertEquals("%E2%82%AC", URLEncoder.encode("\u20AC")); 217 assertEquals("%F0%A0%AE%9F", URLEncoder.encode("\ud842\udf9f", "UTF-8")); 218 assertEquals("%F0%A0%AE%9F", URLEncoder.encode("\ud842\udf9f")); 219 } 220 221 public void testUriDoesNotEncodeNonPrintableNonAsciiCharacters() throws Exception { 222 assertEquals("\u20AC", new URI("http", "foo", "/", "\u20AC").getRawFragment()); 223 assertEquals("\ud842\udf9f", new URI("http", "foo", "/", "\ud842\udf9f").getRawFragment()); 224 } 225 226 public void testUriEncodesControlCharacters() throws Exception { 227 assertEquals("%01", new URI("http", "foo", "/", "\u0001").getRawFragment()); 228 229 // The RI fails this, encoding \u0001 but not \u0000 230 assertEquals("%00", new URI("http", "foo", "/", "\u0000").getRawFragment()); 231 } 232 233 public void testEncodeAndDecode() throws Exception { 234 assertRoundTrip("http://jcltest.apache.org/test?hl=en&q=te st", 235 "http%3A%2F%2Fjcltest.apache.org%2Ftest%3Fhl%3Den%26q%3Dte+st"); 236 assertRoundTrip ("file://a b/c/d.e-f*g_ l", 237 "file%3A%2F%2Fa+b%2Fc%2Fd.e-f*g_+l"); 238 assertRoundTrip("jar:file://a.jar !/b.c/\u1052", 239 "jar%3Afile%3A%2F%2Fa.jar+%21%2Fb.c%2F%E1%81%92"); 240 assertRoundTrip("ftp://test:pwd@localhost:2121/%D0%9C", 241 "ftp%3A%2F%2Ftest%3Apwd%40localhost%3A2121%2F%25D0%259C"); 242 } 243 244 /** 245 * Asserts that {@code original} decodes to {@code decoded} using both URI 246 * and UrlDecoder. 247 */ 248 private void assertDecoded(String decoded, String original) throws Exception { 249 assertEquals(decoded, new URI("http://foo#" + original).getFragment()); 250 assertEquals(decoded, URLDecoder.decode(original)); 251 assertEquals(decoded, URLDecoder.decode(original, "UTF-8")); 252 } 253 254 /** 255 * Asserts that {@code original} encodes to {@code encoded} using both URI 256 * and URLEncoder. 257 */ 258 private void assertEncoded(String encoded, String original) throws Exception { 259 assertEquals(encoded, URLEncoder.encode(original, "UTF-8")); 260 assertEquals(encoded, URLEncoder.encode(original)); 261 assertEquals(encoded, new URI("http", "foo", "/", original).getRawFragment()); 262 } 263 264 private void assertRoundTrip(String original, String encoded) throws Exception { 265 assertEquals(encoded, URLEncoder.encode(original, "UTF-8")); 266 assertEquals(original, URLDecoder.decode(encoded, "UTF-8")); 267 } 268} 269