FileDocCategorySizeDatePackage
ResourceDownloaderURLImpl.javaAPI DocAzureus 3.0.3.417876Fri May 04 18:50:00 BST 2007org.gudy.azureus2.pluginsimpl.local.utils.resourcedownloader

ResourceDownloaderURLImpl

public class ResourceDownloaderURLImpl extends ResourceDownloaderBaseImpl implements SEPasswordListener
author
parg

Fields Summary
private static final int
BUFFER_SIZE
private static final int
MAX_IN_MEM_READ_SIZE
protected URL
original_url
protected boolean
auth_supplied
protected String
user_name
protected String
password
protected InputStream
input_stream
protected boolean
cancel_download
protected boolean
download_initiated
protected long
size
private final String
postData
Constructors Summary
public ResourceDownloaderURLImpl(ResourceDownloaderBaseImpl _parent, URL _url)

	
	 
	
			
									 
	
		this( _parent, _url, false, null, null );
	
public ResourceDownloaderURLImpl(ResourceDownloaderBaseImpl _parent, URL _url, String _user_name, String _password)

		this( _parent, _url, true, _user_name, _password );
	
public ResourceDownloaderURLImpl(ResourceDownloaderBaseImpl _parent, URL _url, boolean _auth_supplied, String _user_name, String _password)

		this(_parent, _url, null, _auth_supplied, _user_name, _password);
	
public ResourceDownloaderURLImpl(ResourceDownloaderBaseImpl _parent, URL _url, String _data, boolean _auth_supplied, String _user_name, String _password)

param
_parent
param
_url
param
_data if null, GET will be used, otherwise POST will be used with the data supplied
param
_auth_supplied
param
_user_name
param
_password

		super( _parent );
		
		/*
		if ( _url.getHost().equals( "212.159.18.92")){
			try{
				_url = new URL(_url.getProtocol() + "://192.168.0.2:" + _url.getPort() + "/" + _url.getPath());
			}catch( Throwable e ){
				
				e.printStackTrace();
			}
		}
		*/
		
		original_url	= _url;
		postData = _data;
		auth_supplied	= _auth_supplied;
		user_name		= _user_name;
		password		= _password;
	
Methods Summary
public voidasyncDownload()

		Thread	t = 
			new AEThread( "ResourceDownloader:asyncDownload")
			{
				public void
				runSupport()
				{
					try{
						download();
						
					}catch ( ResourceDownloaderException e ){
					}
				}
			};
			
		t.setDaemon(true);
		
		t.start();
	
public voidcancel()

		setCancelled();
		
		cancel_download	= true;
		
		try{
			this_mon.enter();
			
			if ( input_stream != null ){
				
				try{
					input_stream.close();
					
				}catch( Throwable e ){
					
				}
			}
		}finally{
			
			this_mon.exit();
		}
		
		informFailed( new ResourceDownloaderException( "Download cancelled" ));
	
public voidclearPasswords()

	
public java.io.InputStreamdownload()

		// System.out.println("ResourceDownloader:download - " + getName());
		
		try{
			reportActivity(this, getLogIndent() + "Downloading: " + original_url );
			
			try{
				this_mon.enter();
				
				if ( download_initiated ){
					
					throw( new ResourceDownloaderException("Download already initiated"));
				}
				
				download_initiated	= true;
				
			}finally{
				
				this_mon.exit();
			}
			
			try{
				URL	url = new URL( original_url.toString().replaceAll( " ", "%20" ));
			      
					// some authentications screw up without an explicit port number here
				
				String	protocol = url.getProtocol().toLowerCase();
				
				if ( url.getPort() == -1 && !protocol.equals( "magnet" )){
					
					int	target_port;
					
					if ( protocol.equals( "http" )){
						
						target_port = 80;
						
					}else{
						
						target_port = 443;
					}
					
					try{
						String str = original_url.toString().replaceAll( " ", "%20" );
					
						int	pos = str.indexOf( "://" );
						
						pos = str.indexOf( "/", pos+4 );
						
							// might not have a trailing "/"
						
						if ( pos == -1 ){
							
							url = new URL( str + ":" + target_port + "/" );
							
						}else{
						
							url = new URL( str.substring(0,pos) + ":" + target_port + str.substring(pos));
						}
												
					}catch( Throwable e ){
						
						Debug.printStackTrace( e );
					}
				}
				
				url = AddressUtils.adjustURL( url );
				
				try{
					if ( auth_supplied ){
						
						SESecurityManager.setPasswordHandler( url, this );
					}

					for (int i=0;i<2;i++){
				
						File					temp_file	= null;

						try{
							HttpURLConnection	con;
							
							if ( url.getProtocol().equalsIgnoreCase("https")){
						      	
									// see ConfigurationChecker for SSL client defaults
				
								HttpsURLConnection ssl_con = (HttpsURLConnection)url.openConnection();
				
									// allow for certs that contain IP addresses rather than dns names
				  	
								ssl_con.setHostnameVerifier(
										new HostnameVerifier()
										{
											public boolean
											verify(
													String		host,
													SSLSession	session )
											{
												return( true );
											}
										});
				  	
								con = ssl_con;
				  	
							}else{
				  	
								con = (HttpURLConnection) url.openConnection();
				  	
							}
							
							con.setRequestProperty("User-Agent", Constants.AZUREUS_NAME + " " + Constants.AZUREUS_VERSION);     
				  
					 		con.setRequestProperty( "Connection", "close" );

							con.addRequestProperty( "Accept-Encoding", "gzip" );
							 
							if (postData != null) {
								con.setDoOutput(true);
								con.setRequestMethod("POST");
								OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream());
								wr.write(postData);
								wr.flush();
							}

							con.connect();
				
							int response = con.getResponseCode();
												
							if ((response != HttpURLConnection.HTTP_ACCEPTED) && (response != HttpURLConnection.HTTP_OK)) {
								
								throw( new ResourceDownloaderException("Error on connect for '" + url.toString() + "': " + Integer.toString(response) + " " + con.getResponseMessage()));    
							}
								
							boolean gzip = false;
							try{
								this_mon.enter();
								
								input_stream = con.getInputStream();
								
								String encoding = con.getHeaderField( "content-encoding");
				 				
				 				gzip = encoding != null && encoding.equalsIgnoreCase("gzip");
				 								 				
				 				if ( gzip ){
				 									 					
				 					input_stream = new GZIPInputStream( input_stream );
				 				}
							}finally{
								
								this_mon.exit();
							}
							
							ByteArrayOutputStream	baos		= null;
							FileOutputStream		fos			= null;
							
							try{
								byte[] buf = new byte[BUFFER_SIZE];
								
								int	total_read	= 0;
								
									// unfortunately not all servers set content length
								
								/* From Apache's mod_deflate doc:
								 * http://httpd.apache.org/docs/2.0/mod/mod_deflate.html
										Note on Content-Length

										If you evaluate the request body yourself, don't trust the
										Content-Length header! The Content-Length header reflects 
										the length of the incoming data from the client and not the
										byte count of the decompressed data stream.
								 */
								int size = gzip ? -1 : con.getContentLength();					
								
								baos = size>0?new ByteArrayOutputStream(size>MAX_IN_MEM_READ_SIZE?MAX_IN_MEM_READ_SIZE:size):new ByteArrayOutputStream();
								
								while( !cancel_download ){
									
									int read = input_stream.read(buf);
										
									if ( read > 0 ){
									
										if ( total_read > MAX_IN_MEM_READ_SIZE ){
											
											if ( fos == null ){
												
												temp_file = AETemporaryFileHandler.createTempFile();
												
												fos = new FileOutputStream( temp_file );
												
												fos.write( baos.toByteArray());
												
												baos = null;
											}
											
											fos.write( buf, 0, read );
											
										}else{
											
											baos.write(buf, 0, read);
										}
										
										total_read += read;
								        
										informAmountComplete( total_read );
										
										if ( size > 0){
											
											informPercentDone(( 100 * total_read ) / size );
										}
									}else{
										
										break;
									}
								}
								
									// if we've got a size, make sure we've read all of it
								
								if ( size > 0 && total_read != size ){
									
									if ( total_read > size ){
										
											// this has been seen with UPnP linksys - more data is read than
											// the content-length has us believe is coming (1 byte in fact...)
										
										Debug.out( "Inconsistent stream length for '" + original_url + "': expected = " + size + ", actual = " + total_read );
										
									}else{
										
										throw( new IOException( "Premature end of stream" ));
									}
								}
							}finally{
								
								if ( fos != null ){
									
									fos.close();
								}
								
								input_stream.close();
							}
				
							InputStream	res;
							
							if ( temp_file != null ){
							
								res = new DeleteFileOnCloseInputStream( temp_file );
								
								temp_file = null;
								
							}else{
								
								res = new ByteArrayInputStream( baos.toByteArray());
							}
							
							boolean	handed_over = false;
							
							try{
								if ( informComplete( res )){
											
									handed_over = true;
									
									return( res );
								}
							}finally{
							
								if ( !handed_over ){
									
									res.close();
								}
							}
							
							throw( new ResourceDownloaderException("Contents downloaded but rejected: '" + original_url + "'" ));
	
						}catch( SSLException e ){
							
							if ( i == 0 ){
								
								if ( SESecurityManager.installServerCertificates( url ) != null ){
									
										// certificate has been installed
									
									continue;	// retry with new certificate
								}
							}

							throw( e );
							
						}finally{
							
							if ( temp_file != null ){
								
								temp_file.delete();
							}
						}
					}
					
					throw( new ResourceDownloaderException("Should never get here" ));
					
				}finally{
							
					if ( auth_supplied ){
								
						SESecurityManager.setPasswordHandler( url, null );
					}
				}
			}catch (java.net.MalformedURLException e){
				
				throw( new ResourceDownloaderException("Exception while parsing URL '" + original_url + "':" + e.getMessage(), e));
				
			}catch (java.net.UnknownHostException e){
				
				throw( new ResourceDownloaderException("Exception while initializing download of '" + original_url + "': Unknown Host '" + e.getMessage() + "'", e));
				
			}catch (java.io.IOException e ){
				
				throw( new ResourceDownloaderException("I/O Exception while downloading '" + original_url + "':" + e.toString(), e ));
			}
		}catch( Throwable e ){
			
			ResourceDownloaderException	rde;
			
			if ( e instanceof ResourceDownloaderException ){
				
				rde = (ResourceDownloaderException)e;
				
			}else{
				
				rde = new ResourceDownloaderException( "Unexpected error", e );
			}
			
			informFailed(rde);
			
			throw( rde );
		}
	
public java.net.PasswordAuthenticationgetAuthentication(java.lang.String realm, java.net.URL tracker)

		if ( user_name == null || password == null ){
			
			String user_info = tracker.getUserInfo();
			
			if ( user_info == null ){
				
				return( null );
			}
			
			String	user_bit	= user_info;
			String	pw_bit		= "";
			
			int	pos = user_info.indexOf(':");
			
			if ( pos != -1 ){
				
				user_bit	= user_info.substring(0,pos);
				pw_bit		= user_info.substring(pos+1);
			}
			
			return( new PasswordAuthentication( user_bit, pw_bit.toCharArray()));
		}
		
		return( new PasswordAuthentication( user_name, password.toCharArray()));
	
public ResourceDownloaderBaseImplgetClone(ResourceDownloaderBaseImpl parent)

		ResourceDownloaderURLImpl c = new ResourceDownloaderURLImpl( parent, original_url, postData, auth_supplied, user_name, password );
		
		c.setSize( size );
		
		c.setProperties( this );
		
		return( c );
	
public java.lang.StringgetName()

		return( original_url.toString());
	
public longgetSize()

			// only every try getting the size once
		
		if ( size == -2 ){
			
			try{
				ResourceDownloaderURLImpl c = (ResourceDownloaderURLImpl)getClone( this );
				
				addReportListener( c );
				
				size = c.getSizeSupport();
				
				setProperties(  c );
				
			}finally{
				
				if ( size == -2 ){
					
					size = -1;
				}
			}
		}
		
		return( size );
	
protected longgetSizeSupport()

		// System.out.println("ResourceDownloader:getSize - " + getName());
		
		try{
			String	protocol = original_url.getProtocol().toLowerCase();
			
			if ( protocol.equals( "magnet" )){
				
				return( -1 );
			}
			
			reportActivity(this, "Getting size of " + original_url );

			try{
				URL	url = new URL( original_url.toString().replaceAll( " ", "%20" ));
			      
				url = AddressUtils.adjustURL( url );

				try{
					if ( auth_supplied ){
	
						SESecurityManager.setPasswordHandler( url, this );
					}
	
					for (int i=0;i<2;i++){
						
						try{
							HttpURLConnection	con;
							
							if ( url.getProtocol().equalsIgnoreCase("https")){
						      	
									// see ConfigurationChecker for SSL client defaults
				
								HttpsURLConnection ssl_con = (HttpsURLConnection)url.openConnection();
				
									// allow for certs that contain IP addresses rather than dns names
				  	
								ssl_con.setHostnameVerifier(
										new HostnameVerifier()
										{
											public boolean
											verify(
													String		host,
													SSLSession	session )
											{
												return( true );
											}
										});
				  	
								con = ssl_con;
				  	
							}else{
				  	
								con = (HttpURLConnection) url.openConnection();
				  	
							}
				  
							con.setRequestMethod( "HEAD" );
							
							con.setRequestProperty("User-Agent", Constants.AZUREUS_NAME + " " + Constants.AZUREUS_VERSION);     
				  
							con.connect();
				
							int response = con.getResponseCode();
							
							if ((response != HttpURLConnection.HTTP_ACCEPTED) && (response != HttpURLConnection.HTTP_OK)) {
								
								throw( new ResourceDownloaderException("Error on connect for '" + url.toString() + "': " + Integer.toString(response) + " " + con.getResponseMessage()));    
							}
															
							setProperty( ResourceDownloader.PR_STRING_CONTENT_TYPE, con.getContentType() );
							
							return( con.getContentLength());
							
						}catch( SSLException e ){
							
							if ( i == 0 ){
								
								if ( SESecurityManager.installServerCertificates( url ) != null ){
									
										// certificate has been installed
									
									continue;	// retry with new certificate
								}
							}

							throw( e );							
						}
					}
					
					throw( new ResourceDownloaderException("Should never get here" ));

				}finally{
					
					if ( auth_supplied ){
					
						SESecurityManager.setPasswordHandler( url, null );
					}
				}
			}catch (java.net.MalformedURLException e){
				
				throw( new ResourceDownloaderException("Exception while parsing URL '" + original_url + "':" + e.getMessage(), e));
				
			}catch (java.net.UnknownHostException e){
				
				throw( new ResourceDownloaderException("Exception while initializing download of '" + original_url + "': Unknown Host '" + e.getMessage() + "'", e));
				
			}catch (java.io.IOException e ){
				
				throw( new ResourceDownloaderException("I/O Exception while downloading '" + original_url + "':" + e.toString(), e ));
			}
		}catch( Throwable e ){
			
			ResourceDownloaderException	rde;
			
			if ( e instanceof ResourceDownloaderException ){
				
				rde = (ResourceDownloaderException)e;
				
			}else{
				
				rde = new ResourceDownloaderException( "Unexpected error", e );
			}
						
			throw( rde );
		}		
	
protected java.net.URLgetURL()

		return( original_url );
	
public voidsetAuthenticationOutcome(java.lang.String realm, java.net.URL tracker, boolean success)

	
protected voidsetProperty(java.lang.String name, java.lang.Object value)

		setPropertySupport( name, value );
	
protected voidsetSize(long l)

		size	= l;