/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 8294241
* @library /test/lib
* @modules java.base/java.net:+open
* @summary Test URL::fromURI(URI, URLStreamHandler)
* @run junit/othervm URLFromURITest
*/
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.VarHandle;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.Locale;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import jdk.test.lib.RandomFactory;
import org.junit.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
public class URLFromURITest {
static final Random RAND = RandomFactory.getRandom();
record TestInput(String uri, URLStreamHandler handler) {
static TestInput withNoHandler(String uri) {
return new TestInput(uri, null );
}
TestInput withCustomHandler() {
return new TestInput(uri(), new CustomStreamHandler());
}
TestInput withUrlPrefix() {return inputWithUrlPrefix(this );}
}
static URI uriWithUrlPrefix(URI uri) {
return URI.create(stringWithUrlPrefix(uri.toString()));
}
static String stringWithUrlPrefix(String uriStr) {
if (uriStr.regionMatches(true , 0, "url:" , 0, 4)) return uriStr;
return RAND.nextBoolean() ? "url:" + uriStr : "Url:" + uriStr;
}
static TestInput inputWithUrlPrefix(TestInput input) {
String uriStr = input.uri();
var handler = input.handler();
var urlUriStr = stringWithUrlPrefix(uriStr);
if (uriStr.equals(urlUriStr)) return null ;
var urlURI = URI.create(urlUriStr);
try {
new URL(null , urlURI.toString(), handler);
} catch (Throwable t) {
System.err.println("skipping new URL(null, \" " + urlURI + " \", handler): " + t);
return null ;
}
return new TestInput(urlUriStr, handler);
}
static Stream<String> uris() {
var uris = Stream.of(
"http://jag:cafebabe@java.sun.com:94/b/c/d?q#g ",
"http://[1080:0:0:0:8:800:200C:417A]/index.html ",
"http://a/b/c/d;p?q ",
"mailto:mduerst@ifi.unizh.ch" ,
"http:comp.infosystems.www.servers.unix" ,
"http://j%41g:cafeb%41be@java.sun.com:94/%41/b/c/d?q#g ",
"jar:file:///x.jar!/",
"jmod:/java.base" ,
"jmod:///java.base");
if (hasFtp()) {
uris = Stream.concat(uris,
Stream.of("ftp://ftp.is.co.za/rfc/rfc1808.txt"));
}
return uris;
}
static Stream<String> nonOverridableUris() {
return Stream.of("file:///nohost/%41/",
"file://with.host/%41/",
"file:/x/y/z" ,
"jrt:/java.base/java/lang/Integer.class" ,
"jrt:///java.base/java/lang/Integer.class");
}
static Stream<TestInput> withNoHandler() {
return Stream.concat(uris(), nonOverridableUris())
.map(TestInput::withNoHandler);
}
static Stream<TestInput> withCustomHandler() {
var withHandlers = uris()
.map(TestInput::withNoHandler)
.map(TestInput::withCustomHandler);
return Stream.concat(withHandlers, Stream.of(
new TestInput("foo:bar:baz" , new CustomStreamHandler()),
new TestInput("jar:file:///x.jar!/", new CustomStreamHandler()),
new TestInput("jar:jar:file///x.jar!/bing", new CustomStreamHandler()),
new TestInput("blah://localhost:80/x/y/z", new CustomStreamHandler())
));
}
static Stream<TestInput> overridingNonOverridable() {
return nonOverridableUris().map(TestInput::withNoHandler)
.map(TestInput::withCustomHandler);
}
@Test
public void checkExceptions() {
var noscheme = URI.create("http" );
var unknown = URI.create("unknown:///foo/bar");
var opaque = URI.create("opaque:opaque-path" );
var jrt = URI.create("jrt:/java.base/java.lang.Integer.class" );
var file = URI.create("file:/" );
var unoscheme = uriWithUrlPrefix(noscheme);
var uunknown = uriWithUrlPrefix(unknown);
var uopaque = uriWithUrlPrefix(opaque);
var ujrt = uriWithUrlPrefix(jrt);
var ufile = uriWithUrlPrefix(file);
var handler = new CustomStreamHandler();
assertThrows(NullPointerException.class , () -> URL.of(null , null ));
assertThrows(NullPointerException.class , () -> URL.of(null , handler));
assertThrows(IllegalArgumentException.class , () -> URL.of(noscheme, null ));
assertThrows(IllegalArgumentException.class , () -> URL.of(noscheme, handler));
assertThrows(IllegalArgumentException.class , () -> URL.of(jrt, handler));
assertThrows(IllegalArgumentException.class , () -> URL.of(file, handler));
assertThrows(IllegalArgumentException.class , () -> URL.of(ujrt, handler));
assertThrows(IllegalArgumentException.class , () -> URL.of(ufile, handler));
assertThrows(MalformedURLException.class , () -> URL.of(unknown, null ));
assertThrows(MalformedURLException.class , () -> URL.of(opaque, null ));
assertThrows(MalformedURLException.class , () -> URL.of(uunknown, null ));
assertThrows(MalformedURLException.class , () -> URL.of(uopaque, null ));
assertThrows(MalformedURLException.class , () -> URL.of(unoscheme, null ));
assertThrows(MalformedURLException.class , () -> URL.of(unoscheme, handler));
}
@ParameterizedTest
@MethodSource(value = "withNoHandler" )
public void testWithNoHandler(TestInput input) throws Exception {
String uriStr = input.uri();
URLStreamHandler handler = input.handler();
System.err.println("testWithNoHandler: " + uriStr);
assertNull(handler, input + ": input handler" );
URI uri = new URI(uriStr);
URL url = URL.of(uri, handler);
checkNoHandler(input, uri, url);
var urlInput = input.withUrlPrefix();
if (urlInput != null ) {
try {
var urlURI = URI.create(input.uri());
checkNoHandler(urlInput, uri, URL.of(urlURI, null ));
} catch (Throwable x) {
throw new AssertionError("Failed: " + urlInput.uri() + " with: " + x, x);
}
}
}
private void checkNoHandler(TestInput input, URI uri, URL url) throws Exception {
System.err.println("Testing: " + uri);
checkURL(input, uri, url);
URLStreamHandler urlHandler = URLAccess.getHandler(url);
assertNotNull(urlHandler, input + ": URL.handler" );
assertNull(urlHandler.getClass().getClassLoader(),
input + ": URL.handler class loader" );
}
@ParameterizedTest
@MethodSource(value = "withCustomHandler" )
public void checkCustomHandler(TestInput input) throws Exception {
String uriStr = input.uri();
URLStreamHandler handler = input.handler();
System.err.println("testWithCustomHandler: " + input);
assertNotNull(handler, input + ": input handler" );
URI uri = new URI(uriStr);
URL url = URL.of(uri, handler);
checkCustomHandler(input, uri, url, handler);
var urlInput = input.withUrlPrefix();
if (urlInput != null ) {
urlInput = urlInput.withCustomHandler();
handler = urlInput.handler();
try {
var urlURI = URI.create(urlInput.uri());
checkCustomHandler(urlInput, uri, URL.of(urlURI, handler), handler);
} catch (Throwable x) {
throw new AssertionError("Failed with handler: " + urlInput.uri() + " with: " + x, x);
}
}
}
private void checkCustomHandler(TestInput input, URI uri, URL url,
URLStreamHandler handler) throws Exception {
System.err.println("Testing: " + uri);
checkURL(input, uri, url);
URLStreamHandler urlHandler = URLAccess.getHandler(url);
assertSame(handler, urlHandler, input + ": URL.handler" );
URLConnection c = url.openConnection();
assertNotNull(c, input + ": opened connection" );
assertEquals(CustomURLConnection.class , c.getClass(),
input + ": connection class" );
assertEquals(CustomStreamHandler.class , urlHandler.getClass(),
input + ": handler class" );
assertEquals(((CustomURLConnection)c).handler, handler, input + ": handler" );
assertEquals(c.getURL(), url, input + ": connection url" );
var customHandler = (CustomStreamHandler)urlHandler;
assertEquals(customHandler.parseURLCalled(), 1, "parseURL calls" );
}
@ParameterizedTest
@MethodSource(value = "overridingNonOverridable" )
public void testOverridingNonOverridable(TestInput input) throws Exception {
String uriStr = input.uri();
URLStreamHandler handler = input.handler();
System.err.println("testOverridingNonOverridable: " + input);
assertNotNull(handler, input + ": input handler" );
URI uri = new URI(uriStr);
try {
URL url = URL.of(uri, handler);
throw new AssertionError("Should not be able to specify handler for: " + uriStr);
} catch (IllegalArgumentException x) {
System.err.println("Got expected exception: " + x);
}
}
private static boolean isFileBased(URI uri) {
String scheme = uri.getScheme();
boolean isJrt = "jrt" .equals(scheme.toLowerCase(Locale.ROOT));
boolean isJmod = "jmod" .equals(scheme.toLowerCase(Locale.ROOT));
boolean isFile = "file" .equals(scheme.toLowerCase(Locale.ROOT));
return isJmod || isJrt || isFile;
}
private static void checkURL(TestInput input, URI uri, URL url) throws MalformedURLException {
String scheme = uri.getScheme();
assertEquals(scheme, url.getProtocol(), input + ": scheme" );
if (uri.isOpaque()) {
String ssp = uri.getSchemeSpecificPart();
assertEquals(ssp, url.getPath(), input + ": ssp" );
} else {
String authority = uri.getRawAuthority();
boolean isHierarchical = uri.toString().startsWith(scheme + "://");
boolean isFileBased = isFileBased(uri);
// Network based URLs usually follow URI, but file based
// protocol handlers have a few discrepancies in how they
// treat an absent authority:
// - URI authority is null if there is no authority, always
// - URL authority is null or empty depending on the protocol
// and on whether the URL is hierarchical or not.
if (isFileBased && authority == null ) {
// jrt: takes a fastpath - so that jrt:/ is equivalent to jrt:///
if (scheme.equals("jrt" )) {
authority = "" ;
}
if (isHierarchical) {
authority = "" ;
}
}
assertEquals(authority, url.getAuthority(), input + ": authority" );
// Network based URLs usually follow URI, but file based
// protocol handlers have a few discrepancies in how they
// treat an absent host:
String host = uri.getHost();
if (isFileBased && host == null ) {
host = "" ;
}
assertEquals(host, url.getHost(), input + ": host" );
if (host != null ) {
String userInfo = uri.getRawUserInfo();
assertEquals(userInfo, url.getUserInfo(), input + ": userInfo" );
assertEquals(uri.getPort(), url.getPort(), input + ": port" );
}
String path = uri.getRawPath();
assertEquals(path, url.getPath(), input + ": path" );
String query = uri.getQuery();
assertEquals(query, url.getQuery(), input + ": query" );
}
String frag = uri.getRawFragment();
assertEquals(frag, url.getRef(), input + ": fragment" );
}
@SuppressWarnings("deprecation" )
private static boolean hasFtp() {
try {
return new java.net.URL("ftp://localhost/") != null;
} catch (java.net.MalformedURLException x) {
System.err.println("FTP not supported by this runtime." );
return false ;
}
}
static class CustomURLConnection extends URLConnection {
public final CustomStreamHandler handler;
CustomURLConnection(CustomStreamHandler handler, URL url) {
super (url);
this .handler = handler;
}
@Override
public void connect() throws IOException {
}
}
static class CustomStreamHandler extends URLStreamHandler {
final AtomicInteger parseURLCalled = new AtomicInteger();
@Override
protected void parseURL(URL u, String spec, int start, int limit) {
parseURLCalled.incrementAndGet();
super .parseURL(u, spec, start, limit);
}
@Override
protected URLConnection openConnection(URL u) throws IOException {
return new CustomURLConnection(this , u);
}
public int parseURLCalled() {
return parseURLCalled.get();
}
}
static final class URLAccess {
static final VarHandle HANDLER;
static {
try {
Lookup lookup = MethodHandles.privateLookupIn(URL.class , MethodHandles.lookup());
HANDLER = lookup.findVarHandle(URL.class , "handler" , URLStreamHandler.class );
} catch (Exception x) {
throw new ExceptionInInitializerError(x);
}
}
static URLStreamHandler getHandler(URL url) {
return (URLStreamHandler)HANDLER.get(url);
}
}
}
quality 92%
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland