/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.squareup.okhttp.internal.http; import com.squareup.okhttp.OkHttpClient; import java.io.IOException; import java.net.CacheRequest; import java.net.CacheResponse; import java.net.HttpURLConnection; import java.net.ResponseCache; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * Exercises HttpURLConnection to convert URL to a URI. Unlike URL#toURI, * HttpURLConnection recovers from URLs with unescaped but unsupported URI * characters like '{' and '|' by escaping these characters. */ public final class URLEncodingTest { /** * This test goes through the exhaustive set of interesting ASCII characters * because most of those characters are interesting in some way according to * RFC 2396 and RFC 2732. http://b/1158780 */ @Test @Ignore public void lenientUrlToUri() throws Exception { // alphanum testUrlToUriMapping("abzABZ09", "abzABZ09", "abzABZ09", "abzABZ09", "abzABZ09"); // control characters testUrlToUriMapping("\u0001", "%01", "%01", "%01", "%01"); testUrlToUriMapping("\u001f", "%1F", "%1F", "%1F", "%1F"); // ascii characters testUrlToUriMapping("%20", "%20", "%20", "%20", "%20"); testUrlToUriMapping("%20", "%20", "%20", "%20", "%20"); testUrlToUriMapping(" ", "%20", "%20", "%20", "%20"); testUrlToUriMapping("!", "!", "!", "!", "!"); testUrlToUriMapping("\"", "%22", "%22", "%22", "%22"); testUrlToUriMapping("#", null, null, null, "%23"); testUrlToUriMapping("$", "$", "$", "$", "$"); testUrlToUriMapping("&", "&", "&", "&", "&"); testUrlToUriMapping("'", "'", "'", "'", "'"); testUrlToUriMapping("(", "(", "(", "(", "("); testUrlToUriMapping(")", ")", ")", ")", ")"); testUrlToUriMapping("*", "*", "*", "*", "*"); testUrlToUriMapping("+", "+", "+", "+", "+"); testUrlToUriMapping(",", ",", ",", ",", ","); testUrlToUriMapping("-", "-", "-", "-", "-"); testUrlToUriMapping(".", ".", ".", ".", "."); testUrlToUriMapping("/", null, "/", "/", "/"); testUrlToUriMapping(":", null, ":", ":", ":"); testUrlToUriMapping(";", ";", ";", ";", ";"); testUrlToUriMapping("<", "%3C", "%3C", "%3C", "%3C"); testUrlToUriMapping("=", "=", "=", "=", "="); testUrlToUriMapping(">", "%3E", "%3E", "%3E", "%3E"); testUrlToUriMapping("?", null, null, "?", "?"); testUrlToUriMapping("@", "@", "@", "@", "@"); testUrlToUriMapping("[", null, "%5B", null, "%5B"); testUrlToUriMapping("\\", "%5C", "%5C", "%5C", "%5C"); testUrlToUriMapping("]", null, "%5D", null, "%5D"); testUrlToUriMapping("^", "%5E", "%5E", "%5E", "%5E"); testUrlToUriMapping("_", "_", "_", "_", "_"); testUrlToUriMapping("`", "%60", "%60", "%60", "%60"); testUrlToUriMapping("{", "%7B", "%7B", "%7B", "%7B"); testUrlToUriMapping("|", "%7C", "%7C", "%7C", "%7C"); testUrlToUriMapping("}", "%7D", "%7D", "%7D", "%7D"); testUrlToUriMapping("~", "~", "~", "~", "~"); testUrlToUriMapping("~", "~", "~", "~", "~"); testUrlToUriMapping("\u007f", "%7F", "%7F", "%7F", "%7F"); // beyond ascii testUrlToUriMapping("\u0080", "%C2%80", "%C2%80", "%C2%80", "%C2%80"); testUrlToUriMapping("\u20ac", "\u20ac", "\u20ac", "\u20ac", "\u20ac"); testUrlToUriMapping("\ud842\udf9f", "\ud842\udf9f", "\ud842\udf9f", "\ud842\udf9f", "\ud842\udf9f"); } @Test @Ignore public void lenientUrlToUriNul() throws Exception { testUrlToUriMapping("\u0000", "%00", "%00", "%00", "%00"); // RI fails this } private void testUrlToUriMapping(String string, String asAuthority, String asFile, String asQuery, String asFragment) throws Exception { if (asAuthority != null) { assertEquals("http://host" + asAuthority + ".tld/", backdoorUrlToUri(new URL("http://host" + string + ".tld/")).toString()); } if (asFile != null) { assertEquals("http://host.tld/file" + asFile + "/", backdoorUrlToUri(new URL("http://host.tld/file" + string + "/")).toString()); } if (asQuery != null) { assertEquals("http://host.tld/file?q" + asQuery + "=x", backdoorUrlToUri(new URL("http://host.tld/file?q" + string + "=x")).toString()); } assertEquals("http://host.tld/file#" + asFragment + "-x", backdoorUrlToUri(new URL("http://host.tld/file#" + asFragment + "-x")).toString()); } private URI backdoorUrlToUri(URL url) throws Exception { final AtomicReference uriReference = new AtomicReference(); OkHttpClient client = new OkHttpClient(); client.setResponseCache(new ResponseCache() { @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { return null; } @Override public CacheResponse get(URI uri, String requestMethod, Map> requestHeaders) throws IOException { uriReference.set(uri); throw new UnsupportedOperationException(); } }); try { HttpURLConnection connection = client.open(url); connection.getResponseCode(); } catch (Exception expected) { if (expected.getCause() instanceof URISyntaxException) { expected.printStackTrace(); } } return uriReference.get(); } }