blob: 1ba96abc51851b7c5c8cc840ba81ac207c0bb12c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.modules.extbrowser;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.net.URL;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.URLMapper;
import org.openide.util.Lookup;
/** Utility class for various useful URL-related tasks.
* <p>There is similar class in extbrowser/webclient module doing almost the same work.
* @author Petr Jiricka
*/
public class URLUtil {
/** results with URLMapper instances*/
private static Lookup.Result result;
static {
result = Lookup.getDefault().lookup(new Lookup.Template (URLMapper.class));
}
/** Creates a URL that is suitable for using in a different process on the
* same node, similarly to URLMapper.EXTERNAL. May just return the original
* URL if that's good enough.
* @param url URL that needs to be displayed in browser
* @param allowJar is <CODE>jar:</CODE> acceptable protocol?
* @return browsable URL or null
*/
public static URL createExternalURL(URL url, boolean allowJar) {
if (url == null)
return null;
URL compliantURL = getFullyRFC2396CompliantURL(url);
// return if the protocol is fine
if (isAcceptableProtocol(compliantURL, allowJar))
return compliantURL;
// remove the anchor
String anchor = compliantURL.getRef();
String urlString = compliantURL.toString ();
int ind = urlString.indexOf('#');
if (ind >= 0) {
urlString = urlString.substring(0, ind);
}
// map to an external URL using the anchor-less URL
try {
FileObject fo = URLMapper.findFileObject(new URL(urlString));
if (fo != null) {
URL newUrl = getURLOfAppropriateType(fo, allowJar);
if (newUrl != null) {
// re-add the anchor if exists
urlString = newUrl.toString();
if (ind >=0) {
urlString = urlString + "#" + anchor; // NOI18N
}
return new URL(urlString);
}
}
}
catch (MalformedURLException e) {
Logger.getLogger("global").log(Level.INFO, null, e);
}
return compliantURL;
}
private static URL getFullyRFC2396CompliantURL(URL url){
String urlStr = url.toString();
int ind = urlStr.indexOf('#');
if (ind > -1) {
String urlWithoutRef = urlStr.substring(0, ind);
try {
String asciiURL = url.toURI().toASCIIString();
// TODO: why not to use just escapedURL = new URL(asciiURL) ?
ind = asciiURL.indexOf('#');
String anchorEscaped = asciiURL.substring(ind);
URL escapedURL = new URL(urlWithoutRef + anchorEscaped);
return escapedURL;
} catch (URISyntaxException | MalformedURLException ex) {
Logger.getLogger("global").log(Level.SEVERE, ex.getMessage(), ex);
}
}
return url;
}
/** Returns a URL for the given file object that can be correctly interpreted
* by usual web browsers (including Netscape 4.71, IE and Mozilla).
* First attempts to get an EXTERNAL URL, if that is a suitable URL, it is used;
* otherwise a NETWORK URL is used.
*/
private static URL getURLOfAppropriateType(FileObject fo, boolean allowJar) {
// PENDING - there is still the problem that the HTTP server will be started
// (because the HttpServerURLMapper.getURL(...) method starts it),
// even when it is not needed
URL retVal;
URL suitable = null;
Iterator instances = result.allInstances ().iterator();
while (instances.hasNext()) {
URLMapper mapper = (URLMapper) instances.next();
retVal = mapper.getURL (fo, URLMapper.EXTERNAL);
if ((retVal != null) && isAcceptableProtocol(retVal, allowJar)) {
// return if this is a 'file' or 'jar' URL
String p = retVal.getProtocol().toLowerCase();
if ("file".equals(p) || "jar".equals(p)) { // NOI18N
return retVal;
}
suitable = retVal;
}
}
// if we found a suitable URL, return it
if (suitable != null) {
return suitable;
}
URL url = URLMapper.findURL(fo, URLMapper.NETWORK);
if (url == null){
Logger.getLogger("global").log(Level.SEVERE, "URLMapper.findURL() failed for " + fo); //NOI18N
return null;
}
return makeURLLocal(url);
}
private static URL makeURLLocal(URL input) {
String host = input.getHost();
try {
if (host.equals(InetAddress.getLocalHost().getHostName())) {
host = "127.0.0.1"; // NOI18N
return new URL(input.getProtocol(), host, input.getPort(), input.getFile());
}
else return input;
} catch (UnknownHostException e) {
return input;
} catch (MalformedURLException e) {
return input;
}
}
/** Returns true if the protocol is acceptable for usual web browsers.
* Specifically, returns true for file, http(s) and ftp protocols.
*/
private static boolean isAcceptableProtocol(URL url, boolean allowJar) {
String protocol = url.getProtocol().toLowerCase();
if ("http".equals(protocol) // NOI18N
|| "https".equals(protocol) // NOI18N
|| "ftp".equals(protocol) // NOI18N
|| "file".equals(protocol)) // NOI18N
return true;
if (allowJar && "jar".equals(protocol)) { // NOI18N
String urlString = url.toString();
if (!urlString.toLowerCase().startsWith("jar:nbinst:")) // NOI18N
return true;
}
return false;
}
/** Determines whether a given browser is capable of displaying URLs with the jar: protocol.
* Currently, Mozilla and Firefox can do this.
* @param browser browser id - one of the constants defined in ExtWebBrowser
* @return true if the browser handles jar URLs
*/
public static boolean browserHandlesJarURLs(String browser) {
return (ExtWebBrowser.MOZILLA.equals(browser) ||
ExtWebBrowser.FIREFOX.equals(browser));
}
}