/*
* 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 );
}
}