/* * Created on Mar 21, 2006 3:09:00 PM * Copyright (C) 2006 Aelitis, All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program 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 for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * AELITIS, SAS au capital de 46,603.30 euros * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. */ package org.gudy.azureus2.core3.util; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.*; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; //import org.bouncycastle.util.encoders.Base64; import org.gudy.azureus2.core3.config.COConfigurationManager; import org.gudy.azureus2.core3.torrent.TOTorrent; //import org.gudy.azureus2.plugins.utils.resourcedownloader.ResourceDownloader; //import org.gudy.azureus2.plugins.utils.resourceuploader.ResourceUploader; import com.aelitis.azureus.core.util.Java15Utils; //import com.aelitis.net.magneturi.MagnetURIHandler; /** * @author TuxPaper * @created Mar 21, 2006 * */ public class UrlUtils { // private static final ThreadPool connect_pool = new ThreadPool( "URLConnectWithTimeout", 8, true ); // // static{ // connect_pool.setWarnWhenFull(); // } // // private static final String[] prefixes = new String[] { // "http://", // "https://", // "ftp://", // "dht://", // "magnet:?", // "magnet://?" }; // // private static int MAGNETURL_STARTS_AT = 3; // dht:// is a form of magnet URL // // private static final Object[] XMLescapes = new Object[] { // new String[] { "&", "&" }, // new String[] { ">", ">" }, // new String[] { "<", "<" }, // new String[] { "\"", """ }, // new String[] { "'", "'" }, // }; // // public static String // getMagnetURI( // byte[] hash ) // { // return( "magnet:?xt=urn:btih:" + Base32.encode( hash )); // } // // /** // * returns magnet uri if input is base 32 or base 16 encoded sha1 hash, null otherwise // * @param base_hash // * @return // */ // // public static String // normaliseMagnetURI( // String base_hash ) // { // byte[] hash = decodeSHA1Hash( base_hash ); // // if ( hash != null ){ // // return( getMagnetURI( hash )); // } // // return( null ); // } // // public static byte[] // decodeSHA1Hash( // String str ) // { // if ( str == null ){ // // return( null ); // } // // str = str.trim(); // // byte[] hash = null; // // try{ // if ( str.length() == 40 ){ // // hash = ByteFormatter.decodeString( str ); // // }else if ( str.length() == 32 ){ // // hash = Base32.decode( str ); // } // }catch( Throwable e ){ // } // // if ( hash != null ){ // // if ( hash.length != 20 ){ // // hash = null; // } // } // // return( hash ); // } // // /** // * test string for possibility that it's an URL. Considers 40 byte hex // * strings as URLs // * // * @param sURL // * @return // */ // public static boolean isURL(String sURL) { // return parseTextForURL(sURL, true) != null; // } // // public static boolean isURL(String sURL, boolean bGuess) { // return parseTextForURL(sURL, true, bGuess) != null; // } // // public static String parseTextForURL(String text, boolean accept_magnets) { // return parseTextForURL(text, accept_magnets, true); // } // // public static String // getURL( // String text ) // { // return( parseTextForURL(text, false, false )); // } // // public static String parseTextForURL(String text, boolean accept_magnets, // boolean guess) { // // if (text == null || text.length() < 5) { // return null; // } // // String href = parseHTMLforURL(text); // if (href != null) { // return href; // } // // try { // text = text.trim(); // text = URLDecoder.decode(text); // } catch (Exception e) { // // sometimes fires a IllegalArgumentException // // catch everything and ignore. // } // // String textLower; // try { // textLower = text.toLowerCase(); // } catch (Throwable e) { // textLower = text; // } // int max = accept_magnets ? prefixes.length : MAGNETURL_STARTS_AT; // int end = -1; // int start = textLower.length(); // String strURL = null; // for (int i = 0; i < max; i++) { // final int testBegin = textLower.indexOf(prefixes[i]); // if (testBegin >= 0 && testBegin < start) { // end = text.indexOf("\n", testBegin + prefixes[i].length()); // String strURLTest = (end >= 0) ? text.substring(testBegin, end - 1) // : text.substring(testBegin); // try { // URL parsedURL = new URL(strURLTest); // strURL = parsedURL.toExternalForm(); // } catch (MalformedURLException e1) { // e1.printStackTrace(); // if (i >= MAGNETURL_STARTS_AT) { // strURL = strURLTest; // } // } // } // } // if (strURL != null) { // return strURL; // } // // if (new File(text).exists()) { // return null; // } // // // accept raw hash of 40 hex chars // if (accept_magnets && text.matches("^[a-fA-F0-9]{40}$")) { // // convert from HEX to raw bytes // byte[] infohash = ByteFormatter.decodeString(text.toUpperCase()); // // convert to BASE32 // return "magnet:?xt=urn:btih:" + Base32.encode(infohash); // } // // // accept raw hash of 32 base-32 chars // if (accept_magnets && text.matches("^[a-zA-Z2-7]{32}$")) { // return "magnet:?xt=urn:btih:" + text; // } // // // javascript:loadOrAlert('WVOPRHRPFSCLAW7UWHCXCH7QNQIU6TWG') // // // accept raw hash of 32 base-32 chars, with garbage around it // if (accept_magnets && guess) { // Pattern pattern = Pattern.compile("[^a-zA-Z2-7][a-zA-Z2-7]{32}[^a-zA-Z2-7]"); // Matcher matcher = pattern.matcher(text); // if (matcher.find()) { // String hash = text.substring(matcher.start() + 1, matcher.start() + 33); // return "magnet:?xt=urn:btih:" + hash; // } // // pattern = Pattern.compile("[^a-fA-F0-9][a-fA-F0-9]{40}[^a-fA-F0-9]"); // matcher = pattern.matcher(text); // if (matcher.find()) { // String hash = text.substring(matcher.start() + 1, matcher.start() + 41); // // convert from HEX to raw bytes // byte[] infohash = ByteFormatter.decodeString(hash.toUpperCase()); // // convert to BASE32 // return "magnet:?xt=urn:btih:" + Base32.encode(infohash); // } // } // // return null; // } // // public static String parseHTMLforURL(String text) { // if (text == null) { // return null; // } // // // examples: // // <A HREF=http://abc.om/moo>test</a> // // <A style=cow HREF="http://abc.om/moo">test</a> // // <a href="http://www.gnu.org/licenses/fdl.html" target="_top">moo</a> // // Pattern pat = Pattern.compile("<.*a\\s++.*href=\"?([^\\'\"\\s>]++).*", // Pattern.CASE_INSENSITIVE); // Matcher m = pat.matcher(text); // if (m.find()) { // String sURL = m.group(1); // try { // sURL = URLDecoder.decode(sURL); // } catch (Exception e) { // // sometimes fires a IllegalArgumentException // // catch everything and ignore. // } // return sURL; // } // // return null; // } // // public static void main(String[] args) { // // MagnetURIHandler.getSingleton(); // byte[] infohash = ByteFormatter.decodeString("1234567890123456789012345678901234567890"); // String[] test = { // "http://moo.com", // "http%3A%2F/moo%2Ecom", // "magnet:?moo", // "magnet%3A%3Fxt=urn:btih:26", // "magnet%3A//%3Fmooo", // "magnet:?xt=urn:btih:" + Base32.encode(infohash), // "aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd", // "magnet:?dn=OpenOffice.org_2.0.3_Win32Intel_install.exe&xt=urn:sha1:PEMIGLKMNFI4HZ4CCHZNPKZJNMAAORKN&xt=urn:tree:tiger:JMIJVWHCQUX47YYH7O4XIBCORNU2KYKHBBC6DHA&xt=urn:ed2k:1c0804541f34b6583a383bb8f2cec682&xl=96793015&xs=http://mirror.switch.ch/ftp/mirror/OpenOffice/stable/2.0.3/OOo_2.0.3_Win32Intel_install.exe" // }; // for (int i = 0; i < test.length; i++) { // System.out.println("decode: " + test[i] + " -> " + URLDecoder.decode(test[i])); // System.out.println("isURL: " + test[i] + " -> " + isURL(test[i])); // System.out.println("parse: " + test[i] + " -> " + parseTextForURL(test[i], true)); // } // // } // // /** // * Like URLEncoder.encode, except translates spaces into %20 instead of + // * @param s // * @return // */ // public static String encode(String s) { // if (s == null) { // return ""; // } // try { // return URLEncoder.encode(s, "UTF-8").replaceAll("\\+", "%20"); // } catch (UnsupportedEncodingException e) { // return URLEncoder.encode(s).replaceAll("\\+", "%20"); // } // } // // public static String decode(String s) { // if (s == null) { // return ""; // } // try { // return( URLDecoder.decode(s, "UTF-8")); // } catch (UnsupportedEncodingException e) { // return( URLDecoder.decode(s)); // } // } // // public static String escapeXML(String s) { // if (s == null) { // return ""; // } // String ret = s; // for (int i = 0; i < XMLescapes.length; i++) { // String[] escapeEntry = (String[])XMLescapes[i]; // ret = ret.replaceAll(escapeEntry[0], escapeEntry[1]); // } // return ret; // } // // public static String unescapeXML(String s) { // if (s == null) { // return ""; // } // String ret = s; // for (int i = 0; i < XMLescapes.length; i++) { // String[] escapeEntry = (String[])XMLescapes[i]; // ret = ret.replaceAll(escapeEntry[1], escapeEntry[0]); // } // return ret; // } // // public static String // convertIPV6Host( // String host ) // { // if ( host.indexOf(':') != -1 ){ // // return( "[" + host + "]" ); // } // // return( host ); // } // // public static String // expandIPV6Host( // String host ) // { // if ( host.indexOf(':') != -1 ){ // // try{ // return( InetAddress.getByAddress(InetAddress.getByName( host ).getAddress()).getHostAddress()); // // }catch( Throwable e ){ // // Debug.printStackTrace(e); // } // } // // return( host ); // } // // public static void // connectWithTimeout( // final URLConnection connection, // long connect_timeout ) // // throws IOException // { // connectWithTimeouts( connection, connect_timeout, -1 ); // } // // public static void // connectWithTimeouts( // final URLConnection connection, // long connect_timeout, // long read_timeout ) // // throws IOException // { // if ( Java15Utils.isAvailable()){ // // if ( connect_timeout != -1 ){ // // Java15Utils.setConnectTimeout( connection, (int)connect_timeout ); // } // // if ( read_timeout != -1 ){ // // Java15Utils.setReadTimeout( connection, (int)read_timeout ); // } // // connection.connect(); // // }else{ // // // TODO: No read timeout support here yet... // // final AESemaphore sem = new AESemaphore( "URLUtils:cwt" ); // // final Throwable[] res = { null }; // // //long start = SystemTime.getMonotonousTime(); // // if ( connect_pool.isFull()){ // // Debug.out( "Connect pool is full, forcing timeout" ); // // throw( new IOException( "Timeout" )); // } // // connect_pool.run( // new AERunnable() // { // public void // runSupport() // { // try{ // connection.connect(); // // }catch( Throwable e ){ // // res[0] = e; // // }finally{ // // sem.release(); // } // } // }); // // boolean ok = sem.reserve( connect_timeout ); // // //long duration = SystemTime.getMonotonousTime() - start; // // //System.out.println( connection.getURL() + ": time=" + duration + ", ok=" + ok ); // // if ( ok ){ // // Throwable error = res[0]; // // if ( error != null ){ // // if ( error instanceof IOException ){ // // throw((IOException)error); // } // // throw( new IOException( Debug.getNestedExceptionMessage( error ))); // } // }else{ // // throw( new IOException( "Timeout" )); // } // } // } // // private static String last_headers = COConfigurationManager.getStringParameter( "metasearch.web.last.headers", null ); // // private static final String default_headers = "SG9zdDogbG9jYWxob3N0OjQ1MTAwClVzZXItQWdlbnQ6IE1vemlsbGEvNS4wIChXaW5kb3dzOyBVOyBXaW5kb3dzIE5UIDUuMTsgZW4tVVM7IHJ2OjEuOC4xLjE0KSBHZWNrby8yMDA4MDQwNCBGaXJlZm94LzIuMC4wLjE0CkFjY2VwdDogdGV4dC94bWwsYXBwbGljYXRpb24veG1sLGFwcGxpY2F0aW9uL3hodG1sK3htbCx0ZXh0L2h0bWw7cT0wLjksdGV4dC9wbGFpbjtxPTAuOCxpbWFnZS9wbmcsKi8qO3E9MC41CkFjY2VwdC1MYW5ndWFnZTogZW4tdXMsZW47cT0wLjUKQWNjZXB0LUVuY29kaW5nOiBnemlwLGRlZmxhdGUKQWNjZXB0LUNoYXJzZXQ6IElTTy04ODU5LTEsdXRmLTg7cT0wLjcsKjtxPTAuNwpLZWVwLUFsaXZlOiAzMDAKQ29ubmVjdGlvbjoga2VlcC1hbGl2ZQ=="; // // public static void // setBrowserHeaders( // ResourceDownloader rd, // String referer ) // { // setBrowserHeaders( rd, null, referer ); // } // // public static void // setBrowserHeaders( // ResourceDownloader rd, // String encoded_headers, // String referer ) // { // String headers_to_use = getBrowserHeadersToUse( encoded_headers ); // // try{ // String header_string = new String( Base64.decode( headers_to_use ), "UTF-8" ); // // String[] headers = header_string.split( "\n" ); // // for (int i=0;i<headers.length;i++ ){ // // String header = headers[i]; // // int pos = header.indexOf( ':' ); // // if ( pos != -1 ){ // // String lhs = header.substring(0,pos).trim(); // String rhs = header.substring(pos+1).trim(); // // if ( !( lhs.equalsIgnoreCase( "Host") || // lhs.equalsIgnoreCase( "Referer" ))){ // // rd.setProperty( "URL_" + lhs, rhs ); // } // } // } // // if ( referer != null && referer.length() > 0 ){ // // rd.setProperty( "URL_Referer", referer ); // } // }catch( Throwable e ){ // } // } // // public static void // setBrowserHeaders( // ResourceUploader ru, // String encoded_headers, // String referer ) // { // String headers_to_use = getBrowserHeadersToUse( encoded_headers ); // // try{ // String header_string = new String( Base64.decode( headers_to_use ), "UTF-8" ); // // String[] headers = header_string.split( "\n" ); // // for (int i=0;i<headers.length;i++ ){ // // String header = headers[i]; // // int pos = header.indexOf( ':' ); // // if ( pos != -1 ){ // // String lhs = header.substring(0,pos).trim(); // String rhs = header.substring(pos+1).trim(); // // if ( !( lhs.equalsIgnoreCase( "Host") || // lhs.equalsIgnoreCase( "Referer" ))){ // // ru.setProperty( "URL_" + lhs, rhs ); // } // } // } // // if ( referer != null && referer.length() > 0 ){ // // ru.setProperty( "URL_Referer", referer ); // } // }catch( Throwable e ){ // } // } // // public static void // setBrowserHeaders( // URLConnection connection, // String referer ) // { // setBrowserHeaders( connection, null, referer ); // } // // public static void // setBrowserHeaders( // URLConnection connection, // String encoded_headers, // String referer ) // { // String headers_to_use = getBrowserHeadersToUse( encoded_headers ); // // try{ // // String header_string = new String( Base64.decode( headers_to_use ), "UTF-8" ); // // String[] headers = header_string.split( "\n" ); // // for (int i=0;i<headers.length;i++ ){ // // String header = headers[i]; // // int pos = header.indexOf( ':' ); // // if ( pos != -1 ){ // // String lhs = header.substring(0,pos).trim(); // String rhs = header.substring(pos+1).trim(); // // if ( !( lhs.equalsIgnoreCase( "Host") || // lhs.equalsIgnoreCase( "Referer" ))){ // // connection.setRequestProperty( lhs, rhs ); // } // } // } // // if ( referer != null && referer.length() > 0 ){ // // connection.setRequestProperty( "Referer", referer ); // } // }catch( Throwable e ){ // } // } // // public static Map // getBrowserHeaders( // String referer ) // { // String headers_to_use = getBrowserHeadersToUse( null ); // // Map result = new HashMap(); // // try{ // // String header_string = new String( Base64.decode( headers_to_use ), "UTF-8" ); // // String[] headers = header_string.split( "\n" ); // // for (int i=0;i<headers.length;i++ ){ // // String header = headers[i]; // // int pos = header.indexOf( ':' ); // // if ( pos != -1 ){ // // String lhs = header.substring(0,pos).trim(); // String rhs = header.substring(pos+1).trim(); // // if ( !( lhs.equalsIgnoreCase( "Host") || // lhs.equalsIgnoreCase( "Referer" ))){ // // result.put( lhs, rhs ); // } // } // } // // if ( referer != null && referer.length() > 0){ // // result.put( "Referer", referer ); // } // }catch( Throwable e ){ // } // // return( result ); // } // // private static String // getBrowserHeadersToUse( // String encoded_headers ) // { // String headers_to_use = encoded_headers; // // synchronized( UrlUtils.class ){ // // if ( headers_to_use == null ){ // // if ( last_headers != null ){ // // headers_to_use = last_headers; // // }else{ // // headers_to_use = default_headers; // } // }else{ // // if ( last_headers == null || !headers_to_use.equals( last_headers )){ // // COConfigurationManager.setParameter( "metasearch.web.last.headers", headers_to_use ); // } // // last_headers = headers_to_use; // } // } // // return( headers_to_use ); // } // // public static boolean queryHasParameter(String query_string, String param_name, boolean case_sensitive) { // if (!case_sensitive) { // query_string = query_string.toLowerCase(); // param_name = param_name.toLowerCase(); // } // if (query_string.charAt(0) == '?') { // query_string = '&' + query_string.substring(1); // } // else if (query_string.charAt(0) != '&') { // query_string = '&' + query_string; // } // // return query_string.indexOf("&" + param_name + "=") != -1; // } // // public static boolean // containsPasskey( // URL url ) // { // String url_str = url.toExternalForm(); // // return( url_str.matches(".*[0-9a-z]{20,40}.*")); // } // // public static URL // setPort( // URL u, // int port ) // { // StringBuffer result = new StringBuffer(); // result.append(u.getProtocol()); // result.append(":"); // String authority=u.getAuthority(); // if (authority != null && authority.length() > 0) { // result.append("//"); // int pos = authority.indexOf( '@' ); // if ( pos != -1 ){ // result.append(authority.substring(0,pos+1)); // authority = authority.substring(pos+1); // } // pos = authority.lastIndexOf(':'); // if ( pos == -1 ){ // result.append(authority + ":" + port ); // }else{ // result.append(authority.substring(0,pos+1) + port ); // } // } // if (u.getPath() != null) { // result.append(u.getPath()); // } // if (u.getQuery() != null) { // result.append('?'); // result.append(u.getQuery()); // } // if (u.getRef() != null) { // result.append("#"); // result.append(u.getRef()); // } // try{ // return( new URL( result.toString())); // }catch( Throwable e ){ // Debug.out(e); // return(u); // } // } // public static URL setHost( URL u, String host ) { StringBuffer result = new StringBuffer(); result.append(u.getProtocol()); result.append(":"); String authority=u.getAuthority(); if (authority != null && authority.length() > 0) { result.append("//"); int pos = authority.indexOf( '@' ); if ( pos != -1 ){ result.append(authority.substring(0,pos+1)); authority = authority.substring(pos+1); } pos = authority.lastIndexOf(':'); if ( pos == -1 ){ result.append(host ); }else{ result.append(host + authority.substring(pos)); } } if (u.getPath() != null) { result.append(u.getPath()); } if (u.getQuery() != null) { result.append('?'); result.append(u.getQuery()); } if (u.getRef() != null) { result.append("#"); result.append(u.getRef()); } try{ return( new URL( result.toString())); }catch( Throwable e ){ Debug.out(e); return(u); } } /** * Returns an explicit IPv4 url if the supplied one has both IPv6 and IPv4 addresses * @param url * @return */ public static URL getIPV4Fallback( URL url ) { try{ InetAddress[] addresses = InetAddress.getAllByName( url.getHost()); if ( addresses.length > 0 ){ InetAddress ipv4 = null; InetAddress ipv6 = null; for ( InetAddress a: addresses ){ if ( a instanceof Inet4Address ){ ipv4 = a; }else{ ipv6 = a; } } if ( ipv4 != null && ipv6 != null ){ url = UrlUtils.setHost( url, ipv4.getHostAddress()); return( url ); } } }catch( Throwable f ){ } return( null ); } public static long getContentLength( HttpURLConnection con ) { long res = con.getContentLength(); if ( res == -1 ){ try{ String str = con.getHeaderField( "content-length" ); if ( str != null ){ res = Long.parseLong( str ); } }catch( Throwable e ){ } } return( res ); } }