/* * Created on Oct 2, 2008 * Created by Paul Gardner * * Copyright 2008 Vuze, Inc. 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; version 2 of the License only. * * 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. */ package com.aelitis.azureus.core.util.http; import java.net.*; import java.nio.charset.Charset; import java.util.*; import java.util.zip.GZIPInputStream; import java.util.zip.InflaterInputStream; import java.io.*; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.gudy.azureus2.core3.security.SESecurityManager; import org.gudy.azureus2.core3.util.*; import com.aelitis.azureus.core.util.CopyOnWriteList; public class HTTPAuthHelper { public static final boolean TRACE = false; public static final int MAX_PROCESSORS = 32; public static final int CONNECT_TIMEOUT = 30*1000; public static final int READ_TIMEOUT = 30*1000; private HTTPAuthHelper parent; private Map children = new HashMap(); private URL delegate_to; private String delegate_to_host; private int delegate_to_port; private boolean delegate_is_https; private Proxy delegate_to_proxy; private CopyOnWriteList listeners = new CopyOnWriteList(); private int port; private ServerSocket server_socket; private boolean http_only_detected; private Map cookie_names_set = new HashMap(); private ThreadPool thread_pool = new ThreadPool("HTTPSniffer", MAX_PROCESSORS, true ); private List processors = new ArrayList(); private volatile boolean destroyed; public HTTPAuthHelper( URL url ) throws Exception { this( null, url ); } private HTTPAuthHelper( HTTPAuthHelper _parent, URL _delegate_to ) throws Exception { parent = _parent; delegate_to = _delegate_to; delegate_to_host = delegate_to.getHost(); delegate_is_https = delegate_to.getProtocol().toLowerCase().equals( "https" ); delegate_to_port = delegate_to.getPort()==-1?delegate_to.getDefaultPort():delegate_to.getPort(); server_socket = new ServerSocket(); server_socket.setReuseAddress( true ); server_socket.bind( new InetSocketAddress( "127.0.0.1", 0 )); port = server_socket.getLocalPort(); } public void setProxy( Proxy _proxy ) { delegate_to_proxy = _proxy; } public void start() { new AEThread2( "HTTPSniffingProxy: " + delegate_to_host + ":" + delegate_to_port + "/" + delegate_is_https + "/" + port, true ) { public void run() { try{ while( !destroyed ){ Socket socket = server_socket.accept(); socket.setSoTimeout( READ_TIMEOUT ); synchronized( HTTPAuthHelper.this ){ if ( processors.size() >= MAX_PROCESSORS ){ try{ Debug.out( "Too many processors" ); socket.close(); }catch( Throwable e ){ } }else{ processor proc = new processor( socket ); processors.add( proc ); proc.start(); } } } }catch( Throwable e ){ if ( !destroyed ){ Debug.printStackTrace( e ); } } } }.start(); } public int getPort() { return( port ); } public boolean wasHTTPOnlyCookieDetected() { return( http_only_detected ); } private void setHTTPOnlyCookieDetected() { http_only_detected = true; if ( parent != null ){ parent.setHTTPOnlyCookieDetected(); } } private String getKey( URL url ) { int child_port = url.getPort()==-1?url.getDefaultPort():url.getPort(); String key = url.getProtocol() + ":" + url.getHost() + ":" + child_port; return( key ); } private HTTPAuthHelper getChild( String url_str, boolean optional ) throws Exception { if ( parent != null ){ return( parent.getChild( url_str,optional )); } String lc_url_str = url_str.toLowerCase(); if ( lc_url_str.startsWith( "http://" ) || lc_url_str.startsWith( "https://")){ URL child_url = new URL( url_str ); String child_key = getKey( child_url ); if ( child_key.equals( getKey( delegate_to ))){ return( this ); } synchronized( this ){ if ( destroyed ){ throw( new Exception( "Destroyed" )); } HTTPAuthHelper child = (HTTPAuthHelper)children.get( child_key ); if ( optional ){ // create children for related domains String base_host = delegate_to.getHost(); String child_host = child_url.getHost(); int base_pos = base_host.lastIndexOf( '.' ); base_pos = base_host.lastIndexOf( '.', base_pos-1 ); int child_pos = child_host.lastIndexOf( '.' ); child_pos = child_host.lastIndexOf( '.', child_pos-1 ); String base_dom = base_host.substring( base_pos, base_host.length()); String child_dom = child_host.substring( child_pos, child_host.length()); if ( base_dom.equals( child_dom )){ optional = false; } } if ( child == null && !optional ){ child = new HTTPAuthHelper( this, new URL( url_str )); children.put( child_key, child ); child.start(); } return( child ); } }else{ //relative return( this ); } } private void addSetCookieName( String name, String value ) { if ( parent != null ){ parent.addSetCookieName( name, value ); }else{ boolean new_entry; synchronized( cookie_names_set ){ trace( "SetCookieName: " + name ); String old_value = (String)cookie_names_set.put( name, value ); new_entry = old_value==null || !old_value.equals( value ); } if ( new_entry ){ Iterator it = listeners.iterator(); while( it.hasNext()){ try{ ((HTTPAuthHelperListener)it.next()).cookieFound( this, name, value ); }catch( Throwable e ){ Debug.printStackTrace(e ); } } } } } private boolean hasSetCookieName( String name ) { if ( parent != null ){ return( parent.hasSetCookieName( name )); }else{ synchronized( cookie_names_set ){ trace( "GetCookieName: " + name ); return( cookie_names_set.containsKey( name )); } } } public void addListener( HTTPAuthHelperListener listener ) { listeners.add( listener ); } public void destroy() { List processors_to_destroy; List chidren_to_destroy; synchronized( this ){ if ( destroyed ){ return; } destroyed = true; chidren_to_destroy = new ArrayList( children.values()); children.clear(); processors_to_destroy = new ArrayList( processors ); processors.clear(); try{ server_socket.close(); }catch( Throwable e ){ } } for (int i=0;i<chidren_to_destroy.size();i++){ try{ ((HTTPAuthHelper)chidren_to_destroy.get(i)).destroy(); }catch( Throwable e ){ } } for (int i=0;i<processors_to_destroy.size();i++){ try{ ((processor)processors_to_destroy.get(i)).destroy(); }catch( Throwable e ){ } } } private class processor { private static final String NL = "\r\n"; private Socket socket_in; private Socket socket_out; private volatile boolean destroyed; private processor( Socket _socket ) { socket_in = _socket; } private void start() { thread_pool.run( new AERunnable() { public void runSupport() { try{ sniff(); }finally{ synchronized( HTTPAuthHelper.this ){ processors.remove( processor.this ); } } } }); } private void sniff() { try{ InputStream is = socket_in.getInputStream(); String request_header = readHeader( is ); connectToDelegate(); process( request_header ); }catch( Throwable e ){ if ( !( e instanceof IOException )){ Debug.out( e ); } destroy(); } } private void connectToDelegate() throws IOException { try{ if ( delegate_is_https ){ TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, RandomUtils.SECURE_RANDOM ); SSLSocketFactory factory = sc.getSocketFactory(); try{ if ( delegate_to_proxy == null ){ socket_out = factory.createSocket(); socket_out.connect( new InetSocketAddress( delegate_to_host, delegate_to_port ), CONNECT_TIMEOUT ); }else{ Socket plain_socket = new Socket( delegate_to_proxy ); plain_socket.connect( new InetSocketAddress( delegate_to_host, delegate_to_port ), CONNECT_TIMEOUT ); socket_out = factory.createSocket( plain_socket, delegate_to_host, delegate_to_port, true ); } }catch( SSLException ssl_excep ){ if ( socket_out != null ){ try{ socket_out.close(); }catch( Throwable e ){ } } factory = SESecurityManager.installServerCertificates( "AZ-sniffer:" + delegate_to_host + ":" + port, delegate_to_host, delegate_to_port ); if ( delegate_to_proxy == null ){ socket_out = factory.createSocket(); socket_out.connect( new InetSocketAddress( delegate_to_host, delegate_to_port ), CONNECT_TIMEOUT ); }else{ Socket plain_socket = new Socket( delegate_to_proxy ); plain_socket.connect( new InetSocketAddress( delegate_to_host, delegate_to_port ), CONNECT_TIMEOUT ); socket_out = factory.createSocket( plain_socket, delegate_to_host, delegate_to_port, true ); } } }else{ if ( delegate_to_proxy == null ){ socket_out = new Socket(); }else{ socket_out = new Socket( delegate_to_proxy ); } socket_out.connect( new InetSocketAddress( delegate_to_host, delegate_to_port ), CONNECT_TIMEOUT ); } }catch( Throwable e ){ if ( e instanceof IOException ){ throw((IOException)e ); } throw( new IOException( e.toString())); }finally{ if ( socket_out != null ){ synchronized( this ){ if ( destroyed ){ try{ socket_out.close(); }catch( Throwable e ){ }finally{ socket_out = null; } throw( new IOException( "destroyed" )); } } } } } private void process( String request_header ) throws Exception { final OutputStream target_os = socket_out.getOutputStream(); String[] request_lines = splitHeader( request_header ); String target_url = request_lines[0]; int space_pos = target_url.indexOf(' '); if ( space_pos == -1 ){ System.out.println( "eh?" ); } target_url = target_url.substring( space_pos ).trim(); space_pos = target_url.indexOf(' '); target_url = target_url.substring( 0, space_pos ).trim(); trace( "Page request for " + target_url ); List cookies_to_remove = new ArrayList(); for (int i=0;i<request_lines.length;i++){ String line_out = request_lines[i]; String line_in = line_out.trim().toLowerCase(); String[] bits = line_in.split(":"); if ( bits.length >= 2 ){ String lhs = bits[0].trim(); if ( lhs.equals( "host" )){ String port_str; if ( delegate_to_port == 80 || delegate_to_port == 443 ){ port_str = ""; }else{ port_str = ":" + delegate_to_port; } line_out = "Host: " + delegate_to_host + port_str; }else if ( lhs.equals( "connection" )){ line_out = "Connection: close"; }else if ( lhs.equals( "referer" )){ String page = line_out.substring( line_out.indexOf( ':' )+1).trim(); page = page.substring( page.indexOf( "://") + 3); int pos = page.indexOf( '/' ); if ( pos >= 0 ){ page = page.substring( pos ); }else{ page = "/"; } String port_str; if ( delegate_to_port == 80 || delegate_to_port == 443 ){ port_str = ""; }else{ port_str = ":" + delegate_to_port; } line_out = "Referer: http" + (delegate_is_https?"s":"") + "://" + delegate_to_host + port_str + page; }else if ( lhs.equals( "cookie" )){ String cookies_str = line_out.substring( line_out.indexOf( ':' )+1).trim(); String[] cookies = cookies_str.split( ";" ); String cookies_out = ""; for (int j=0;j<cookies.length;j++){ String cookie = cookies[j]; String name = cookie.split( "=" )[0].trim(); if ( hasSetCookieName( name )){ cookies_out += (cookies_out.length()==0?"":"; ") + cookie; }else{ cookies_to_remove.add( name ); } } if ( cookies_out.length() > 0 ){ line_out = "Cookie: " + cookies_out; }else{ line_out = null; } } } if ( line_out != null ){ trace( "-> " + line_out ); target_os.write((line_out+NL).getBytes()); } } target_os.write( NL.getBytes()); target_os.flush(); new AEThread2( "HTTPSniffingProxy:proc:2", true ) { public void run() { try{ InputStream source_is = socket_in.getInputStream(); byte[] buffer = new byte[32000]; while( !destroyed ){ int len = source_is.read( buffer ); if ( len <= 0 ){ break; } target_os.write( buffer, 0, len ); trace( "POST:" + new String( buffer, 0, len )); } }catch( Throwable e ){ } } }.start(); InputStream target_is = socket_out.getInputStream(); OutputStream source_os = socket_in.getOutputStream(); String reply_header = readHeader( target_is ); String[] reply_lines = splitHeader( reply_header ); String content_type = null; String content_charset = "ISO-8859-1"; for (int i=0;i<reply_lines.length;i++){ String line_in = reply_lines[i].trim().toLowerCase(); String[] bits = line_in.split(":"); if ( bits.length >= 2 ){ String lhs = bits[0].trim(); if ( lhs.equals( "content-type" )){ String rhs = reply_lines[i].substring( line_in.indexOf( ':' ) + 1 ).trim(); String[] x = rhs.split( ";" ); content_type = x[0]; if ( x.length > 1 ){ int pos = rhs.toLowerCase().indexOf( "charset" ); if ( pos >= 0 ){ String cc = rhs.substring( pos+1 ); pos = cc.indexOf('='); if ( pos != -1 ){ cc = cc.substring( pos+1 ).trim(); if ( Charset.isSupported( cc )){ content_charset = cc; } } } } } } } boolean rewrite = false; boolean chunked = false; String content_encoding = null; if ( content_type == null ){ rewrite = true; }else{ content_type = content_type.toLowerCase(); if ( content_type.indexOf( "text/" ) != -1 ){ rewrite = true; } } for (int i=0;i<reply_lines.length;i++){ String line_out = reply_lines[i]; String line_in = line_out.trim().toLowerCase(); String[] bits = line_in.split(":"); if ( bits.length >= 2 ){ String lhs = bits[0].trim(); if ( lhs.equals( "set-cookie" )){ String cookies_in = line_out.substring( line_out.indexOf( ':' )+1 ); String[] cookies; if ( cookies_in.toLowerCase().indexOf( "expires" ) == -1 ){ cookies = cookies_in.split( "," ); }else{ cookies = new String[]{ cookies_in }; } String cookies_out = ""; for (int c=0;c<cookies.length;c++){ String cookie = cookies[c]; String[] x = cookie.split( ";" ); String modified_cookie = ""; for (int j=0;j<x.length;j++){ String entry = x[j].trim(); if ( entry.equalsIgnoreCase( "httponly" )){ setHTTPOnlyCookieDetected(); }else if ( entry.equalsIgnoreCase( "secure" )){ }else if ( entry.toLowerCase().startsWith( "domain" )){ // remove domain restriction so cookie sent to localhost }else if ( entry.toLowerCase().startsWith( "expires" )){ // force to be session cookie otherwise we'll end up sending // cookies from multiple sites to 'localhost' }else{ if ( j == 0 ){ int pos = entry.indexOf( '=' ); String name = entry.substring( 0, pos ).trim(); String value = entry.substring( pos+1 ).trim(); addSetCookieName( name, value ); } modified_cookie += (modified_cookie.length()==0?"":"; ") + entry; } } cookies_out += (c==0?"":", " ) + modified_cookie; } line_out = "Set-Cookie: " + cookies_out; }else if ( lhs.equals( "set-cookie2" )){ // http://www.ietf.org/rfc/rfc2965.txt // one or more comma separated String cookies_in = line_out.substring( line_out.indexOf( ':' )+1 ); String[] cookies = cookies_in.split( "," ); String cookies_out = ""; for (int c=0;c<cookies.length;c++){ String cookie = cookies[c]; String[] x = cookie.split( ";" ); String modified_cookie = ""; for (int j=0;j<x.length;j++){ String entry = x[j].trim(); if ( entry.equalsIgnoreCase( "secure" )){ }else if ( entry.equalsIgnoreCase( "discard" )){ }else if ( entry.toLowerCase().startsWith( "domain" )){ }else if ( entry.toLowerCase().startsWith( "port" )){ }else{ if ( j == 0 ){ int pos = entry.indexOf( '=' ); String name = entry.substring( 0, pos ).trim(); String value = entry.substring( pos+1 ).trim(); addSetCookieName( name, value ); } modified_cookie += (modified_cookie.length()==0?"":"; ") + entry; } } cookies_out += (c==0?"":", " ) + modified_cookie + "; Discard"; } line_out = "Set-Cookie2: " + cookies_out; }else if ( lhs.equals( "connection" )){ line_out = "Connection: close"; }else if ( lhs.equals( "location" )){ String page = line_out.substring( line_out.indexOf( ':' )+1).trim(); String child_url = page.trim(); HTTPAuthHelper child = getChild( child_url, false ); int pos = page.indexOf( "://" ); if ( pos >= 0 ){ // absolute page = page.substring( pos + 3); pos = page.indexOf( '/' ); if ( pos >= 0 ){ page = page.substring( pos ); }else{ page = "/"; } }else{ // relative. actually illegal as must be absolute if ( !page.startsWith( "/" )){ String temp = target_url; int marker = temp.indexOf( "://" ); if ( marker != -1 ){ // strip out absolute part temp = temp.substring( marker + 3 ); marker = temp.indexOf( "/" ); if ( marker == -1 ){ temp = "/"; }else{ temp = temp.substring( marker ); } }else{ if ( !temp.startsWith( "/" )){ temp = "/" + temp; } } marker = temp.lastIndexOf( "/" ); if ( marker >= 0 ){ temp = temp.substring( 0, marker+1 ); } page = temp + page; } } line_out = "Location: http://127.0.0.1:" + child.getPort() + page; }else if ( lhs.equals( "content-encoding" )){ if ( rewrite ){ String encoding = bits[1].trim(); if ( encoding.equalsIgnoreCase( "gzip" ) || encoding.equalsIgnoreCase( "deflate" )){ content_encoding = encoding; line_out = null; } } }else if ( lhs.equals( "content-length" )){ if ( rewrite ){ line_out = null; } }else if ( lhs.equals( "transfer-encoding" )){ if ( bits[1].indexOf( "chunked" ) != -1 ){ chunked = true; if ( rewrite ){ line_out = null; } } } } if ( line_out != null ){ trace( "<- " + line_out ); source_os.write((line_out+NL).getBytes()); } } for ( int i=0;i<cookies_to_remove.size();i++ ){ String name = (String)cookies_to_remove.get(i); if ( !hasSetCookieName( name )){ String remove_str = "Set-Cookie: " + name + "=X; expires=Sun, 01 Jan 2000 01:00:00 GMT"; trace( "<- (cookie removal) " + remove_str ); source_os.write((remove_str+NL).getBytes()); remove_str = "Set-Cookie2: " + name + "=X; Max-Age=0; Version=1"; trace( "<- (cookie removal) " + remove_str ); source_os.write((remove_str+NL).getBytes()); } } byte[] buffer = new byte[32000]; if ( rewrite ){ StringBuffer sb = new StringBuffer(); if ( chunked ){ // chunking uses ISO-8859-1 while( true ){ int len = target_is.read( buffer ); if ( len <= 0 ){ break; } sb.append(new String( buffer, 0, len, "ISO-8859-1" )); } StringBuffer sb_dechunked = new StringBuffer( sb.length()); String chunk = ""; int total_length = 0; int sb_pos = 0; while( sb_pos < sb.length()){ chunk += sb.charAt( sb_pos++ ); // second time around the chunk will be prefixed with NL // from end of previous // so make sure we ignore this if ( chunk.endsWith( NL ) && chunk.length() > 2 ){ int semi_pos = chunk.indexOf( ';' ); if ( semi_pos != -1 ){ chunk = chunk.substring( 0, semi_pos ); } chunk = chunk.trim(); int chunk_length = Integer.parseInt( chunk, 16 ); if ( chunk_length <= 0 ){ break; } total_length += chunk_length; if ( total_length > 2*1024*1024 ){ throw (new IOException("Chunk size " + chunk_length + " too large")); } char[] chunk_buffer = new char[chunk_length]; sb.getChars( sb_pos, sb_pos + chunk_length, chunk_buffer, 0 ); sb_dechunked.append( chunk_buffer ); sb_pos += chunk_length; chunk = ""; } } // dechunked ISO-8859-1 - unzip if required and then apply correct charset target_is = new ByteArrayInputStream( sb_dechunked.toString().getBytes( "ISO-8859-1" )); } if ( content_encoding != null ){ if ( content_encoding.equalsIgnoreCase( "gzip" )){ target_is = new GZIPInputStream( target_is ); }else if ( content_encoding.equalsIgnoreCase( "deflate" )){ target_is = new InflaterInputStream( target_is ); } } sb.setLength(0); while( !destroyed ){ int len = target_is.read( buffer ); if ( len <= 0 ){ break; } sb.append(new String( buffer, 0, len, content_charset )); } String str = sb.toString(); String lc_str = str.toLowerCase(); StringBuffer result = null; int str_pos = 0; // FileUtil.writeBytesAsFile( "C:\\temp\\xxx" + new Random().nextInt(100000) + ".txt", str.getBytes()); while( true ){ // http://a.b int url_start = str.length() - str_pos >=10?lc_str.indexOf( "http", str_pos ):-1; if ( url_start == -1 ){ break; } int match_pos; if ( lc_str.charAt( url_start + 4 ) == 's' ){ match_pos = url_start + 5; }else{ match_pos = url_start + 4; } if ( lc_str.substring( match_pos, match_pos+3 ).equals( "://" )){ int url_end = -1; for (int i=match_pos+3;;i++){ char c = lc_str.charAt(i); if ( c == '/' ){ url_end = i+1; break; }else if ( c == '.' || c == '-' || c == ':' ){ }else if ( c >= '0' && c <= '9' ){ }else if ( c >= 'a' && c <= 'z' ){ }else{ url_end = i; break; } if ( i == lc_str.length()-1 ){ url_end = i; } } if ( url_end > url_start ){ String url_str = str.substring( url_start, url_end ); boolean appended = false; try{ // make sure vald URL URL url = new URL( url_str ); if ( url.getHost().length() > 0 ){ boolean existing_only = true; // override if form action or meta for (int i=url_start-1;i>=0&&url_start-i<512;i--){ if ( lc_str.charAt( i ) == '<' ){ String prefix = lc_str.substring(i, url_start); if ( prefix.indexOf( "form" ) != -1 ){ existing_only = false; }else if ( prefix.indexOf( "meta" ) != -1 && prefix.indexOf( "http-equiv" ) != -1 ){ existing_only = false; } break; } } HTTPAuthHelper child = getChild( url_str, existing_only ); if ( child != null ){ String replacement = "http://127.0.0.1:" + child.getPort(); if ( url_str.endsWith( "/" )){ replacement += "/"; } if ( result == null ){ result = new StringBuffer( str.length()); if ( url_start > 0 ){ result.append( str.subSequence( 0, url_start )); } }else if ( url_start > str_pos ){ result.append( str.subSequence( str_pos, url_start )); } trace( "Replacing " + url_str + " with " + replacement ); result.append( replacement ); appended = true; }else{ trace( " No child for " + url_str ); } } }catch( Throwable e ){ } if ( result != null && !appended ){ result.append( str.subSequence( str_pos, url_end )); } str_pos = url_end; }else{ break; } }else{ if ( result != null ){ result.append( str.subSequence( str_pos, match_pos )); } str_pos = match_pos; } } if ( result != null ){ if ( str_pos < str.length() ){ result.append( str.subSequence( str_pos, str.length())); } sb = result; } source_os.write( ( "Content-Length: " + sb.length() + NL ).getBytes()); source_os.write( NL.getBytes()); source_os.write( sb.toString().getBytes( content_charset )); }else{ source_os.write( NL.getBytes()); while( !destroyed ){ int len = target_is.read( buffer ); if ( len <= 0 ){ break; } source_os.write( buffer, 0, len ); } } } private String readHeader( InputStream is ) throws IOException { String header = ""; byte[] buffer = new byte[1]; boolean found = false; while( true ){ if ( is.read( buffer ) != 1 ){ break; } header += (char)buffer[0]; if ( header.endsWith( NL + NL )){ found = true; break; } } if ( !found ){ throw( new IOException( "End of stream reading header" )); } return( header ); } private String[] splitHeader( String str ) { String[] bits = str.split( NL ); return( bits ); } private void destroy() { synchronized( this ){ if ( destroyed ){ return; } destroyed = true; } if ( socket_out != null ){ try{ socket_out.close(); }catch( Throwable e ){ } } try{ socket_in.close(); }catch( Throwable e ){ } } } private void trace( String str ) { if ( TRACE ){ System.out.println( str ); } } public static void main( String[] args ) { try{ HTTPAuthHelper proxy = new HTTPAuthHelper( new URL( "https://client.vuze.com/" )); proxy.start(); System.out.println( "port=" + proxy.getPort()); while( true ){ Thread.sleep(1000); } }catch( Throwable e ){ e.printStackTrace(); } } }