Package com.aelitis.azureus.plugins.extseed.util

Source Code of com.aelitis.azureus.plugins.extseed.util.ExternalSeedHTTPDownloaderRange

/*
* Created on 16-Dec-2005
* Created by Paul Gardner
* Copyright (C) 2005, 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 com.aelitis.azureus.plugins.extseed.util;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Socket;
import java.net.URL;
import java.util.StringTokenizer;

import org.gudy.azureus2.core3.security.SEPasswordListener;
import org.gudy.azureus2.core3.security.SESecurityManager;
import org.gudy.azureus2.core3.util.Debug;

import com.aelitis.azureus.core.util.Java15Utils;
import com.aelitis.azureus.plugins.extseed.ExternalSeedException;

public class
ExternalSeedHTTPDownloaderRange
  implements ExternalSeedHTTPDownloader, SEPasswordListener
{
  public static final String  NL = "\r\n";
 

  private URL      original_url;
  private String    user_agent;
 
  private URL      redirected_url;
  private int      consec_redirect_fails;
 
  private int      last_response;
  private int      last_response_retry_after_secs;
     
  public
  ExternalSeedHTTPDownloaderRange(
    URL    _url,
    String  _user_agent )
  {
    original_url  = _url;
    user_agent    = _user_agent;
  }
 
  public URL
  getURL()
  {
    return( original_url );
  }
 
  public void
  download(
    int                  length,
    ExternalSeedHTTPDownloaderListener  listener,
    boolean                con_fail_is_perm_fail )
 
    throws ExternalSeedException
  {
    download( new String[0], new String[0], length, listener, con_fail_is_perm_fail );
  }
 
  public void
  downloadRange(
    long                offset,
    int                  length,
    ExternalSeedHTTPDownloaderListener  listener,
    boolean                con_fail_is_perm_fail )
 
    throws ExternalSeedException
  {
    download(   new String[]{ "Range" }, new String[]{ "bytes=" + offset + "-" + (offset+length-1)},
          length,
          listener,
          con_fail_is_perm_fail );
  }
 
  public void
  download(
    String[]              prop_names,
    String[]              prop_values,
    int                  length,
    ExternalSeedHTTPDownloaderListener  listener,
    boolean                con_fail_is_perm_fail )
 
    throws ExternalSeedException
  {
    boolean  connected = false;
   
    InputStream  is  = null;
       
    String  outcome = "";
   
    try{
      SESecurityManager.setThreadPasswordHandler( this );
     
      // System.out.println( "Connecting to " + url + ": " + Thread.currentThread().getId());

      HttpURLConnection  connection;
      int          response;
     
      while( true ){
       
        URL  target = redirected_url==null?original_url:redirected_url;
       
        connection = (HttpURLConnection)target.openConnection();
       
        connection.setRequestProperty( "Connection", "Keep-Alive" );
        connection.setRequestProperty( "User-Agent", user_agent );
       
        for (int i=0;i<prop_names.length;i++){
         
          connection.setRequestProperty( prop_names[i], prop_values[i] );
        }
       
        int  time_remaining  = listener.getPermittedTime();
       
        if ( time_remaining > 0 ){
         
          Java15Utils.setConnectTimeout( connection, time_remaining );
        }
             
        connection.connect();
     
        time_remaining  = listener.getPermittedTime();
                 
        if ( time_remaining < 0 ){
         
          throw( new IOException( "Timeout during connect" ));
        }
       
        Java15Utils.setReadTimeout( connection, time_remaining );
           
        connected  = true;
       
        response = connection.getResponseCode();

        if response == HttpURLConnection.HTTP_ACCEPTED ||
            response == HttpURLConnection.HTTP_OK ||
            response == HttpURLConnection.HTTP_PARTIAL ){
         
          if ( redirected_url != null ){
           
            consec_redirect_fails = 0;
          }
         
          break;
        }
       
        if ( redirected_url == null ){
         
          break;
        }
       
          // try again with original URL
       
        consec_redirect_fails++;
       
        redirected_url = null;
      }
     
      URL final_url = connection.getURL();
     
      if ( consec_redirect_fails < 10 && !original_url.toExternalForm().equals( final_url.toExternalForm())){
       
        redirected_url = final_url;
      }
     
      last_response  = response;
     
      last_response_retry_after_secs  = -1;
     
            if ( response == 503 ){
                          
                  // webseed support for temp unavail - read the retry_after
             
              long retry_after_date = new Long(connection.getHeaderFieldDate("Retry-After", -1L)).longValue();
             
                if ( retry_after_date <= -1 ){
                 
                  last_response_retry_after_secs = connection.getHeaderFieldInt("Retry-After", -1);
                   
                }else{
                 
                  last_response_retry_after_secs = (int)((retry_after_date - System.currentTimeMillis())/1000);
                 
                  if ( last_response_retry_after_secs < 0 ){
                   
                    last_response_retry_after_secs = -1;
                  }
                }
            }
           
      is = connection.getInputStream();
     
      if (   response == HttpURLConnection.HTTP_ACCEPTED ||
          response == HttpURLConnection.HTTP_OK ||
          response == HttpURLConnection.HTTP_PARTIAL ){
               
        int  pos = 0;
       
        byte[]  buffer     = null;
        int    buffer_pos  = 0;
        int    buffer_len  = 0;

        while( pos < length ){
         
          if ( buffer == null ){
           
            buffer     = listener.getBuffer();           
            buffer_pos  = listener.getBufferPosition();
            buffer_len  = listener.getBufferLength();
          }

          listener.setBufferPosition( buffer_pos );
         
          int  to_read = buffer_len - buffer_pos;
         
          int  permitted = listener.getPermittedBytes();
         
          if ( permitted < to_read ){
           
            to_read  = permitted;
          }
         
          int  len = is.read( buffer, buffer_pos, to_read );
         
          if ( len < 0 ){
           
            break;
          }
         
          listener.reportBytesRead( len );
         
          pos  += len;
         
          buffer_pos  += len;
         
          if ( buffer_pos == buffer_len ){
           
            listener.done();
           
            buffer    = null;
            buffer_pos  = 0;
          }
        }
       
        if ( pos != length ){
         
          String  log_str;
         
          if ( buffer == null ){
           
            log_str = "No buffer assigned";
           
          }else{
           
            log_str =  new String( buffer, 0, length );
           
            if ( log_str.length() > 64 ){
             
              log_str = log_str.substring( 0, 64 );
            }
          }
         
          outcome = "Connection failed: data too short - " + length + "/" + pos + " [" + log_str + "]";
         
          throw( new ExternalSeedException( outcome ));
        }
       
        outcome = "read " + pos + " bytes";
       
        // System.out.println( "download length: " + pos );
       
      }else{
       
        outcome = "Connection failed: " + connection.getResponseMessage();
       
        ExternalSeedException  error = new ExternalSeedException( outcome );
       
        error.setPermanentFailure( true );
       
        throw( error );
      }
    }catch( IOException e ){
     
      if ( con_fail_is_perm_fail && !connected ){
       
        outcome = "Connection failed: " + e.getMessage();
       
        ExternalSeedException  error = new ExternalSeedException( outcome );
       
        error.setPermanentFailure( true );
       
        throw( error );

      }else{
       
        outcome =  "Connection failed: " + Debug.getNestedExceptionMessage( e );
               
                if ( last_response_retry_after_secs >= 0){
                 
                    outcome += ", Retry-After: " + last_response_retry_after_secs + " seconds";
                }
                       
        ExternalSeedException excep = new ExternalSeedException( outcome, e );
       
        if ( e instanceof FileNotFoundException ){
         
          excep.setPermanentFailure( true );
        }
       
        throw( excep );
      }
    }catch( Throwable e ){
     
      if ( e instanceof ExternalSeedException ){
       
        throw((ExternalSeedException)e);
      }
     
      outcome = "Connection failed: " + Debug.getNestedExceptionMessage( e );
     
      throw( new ExternalSeedException("Connection failed", e ));
     
    }finally{
     
      SESecurityManager.unsetThreadPasswordHandler();

      // System.out.println( "Done to " + url + ": " + Thread.currentThread().getId() + ", outcome=" + outcome );

      if ( is != null ){
       
        try{
          is.close();
         
        }catch( Throwable e ){
         
        }
      }
    }
  }
 
  public void
  downloadSocket(
    int                  length,
    ExternalSeedHTTPDownloaderListener  listener,
    boolean                con_fail_is_perm_fail )
           
      throws ExternalSeedException
  {
    downloadSocket( new String[0], new String[0], length, listener, con_fail_is_perm_fail );
  }
 
  public void
  downloadSocket(
    String[]              prop_names,
    String[]              prop_values,
    int                  length,
    ExternalSeedHTTPDownloaderListener  listener,
    boolean                con_fail_is_perm_fail )
 
    throws ExternalSeedException
  {
    Socket  socket  = null;
   
    boolean  connected = false;
   
    try{       
      String  output_header =
        "GET " + original_url.getPath() + "?" + original_url.getQuery() + " HTTP/1.1" + NL +
        "Host: " + original_url.getHost() + (original_url.getPort()==-1?"":( ":" + original_url.getPort())) + NL +
        "Accept: */*" + NL +
        "Connection: Close" + NL +  // if we want to support keep-alive we'll need to implement a socket cache etc.
        "User-Agent: " + user_agent + NL;
   
      for (int i=0;i<prop_names.length;i++){
       
        output_header += prop_names[i] + ":" + prop_values[i] + NL;
      }
     
      output_header += NL;
     
      int  time_remaining  = listener.getPermittedTime();
     
      if ( time_remaining > 0 ){
       
        socket = new Socket();
       
        socket.connect( new InetSocketAddress( original_url.getHost(), original_url.getPort()==-1?original_url.getDefaultPort():original_url.getPort()), time_remaining );
       
      }else{
   
        socket = new Socketoriginal_url.getHost(), original_url.getPort()==-1?original_url.getDefaultPort():original_url.getPort());
      }
     
      connected  = true;
     
      time_remaining  = listener.getPermittedTime();

      if ( time_remaining < 0 ){
         
        throw( new IOException( "Timeout during connect" ));
       
      }else if ( time_remaining > 0 ){
       
        socket.setSoTimeout( time_remaining );
      }
     
      OutputStream  os = socket.getOutputStream();
     
      os.write( output_header.getBytes( "ISO-8859-1" ));
     
      os.flush();
     
      InputStream is = socket.getInputStream();
     
      try{
        String  input_header = "";
       
        while( true ){
         
          byte[]  buffer = new byte[1];
         
          int  len = is.read( buffer );
         
          if ( len < 0 ){
           
            throw( new IOException( "input too short reading header" ));
          }
         
          input_header  += (char)buffer[0];
         
          if ( input_header.endsWith(NL+NL)){
         
            break;
          }
        }
               
        // HTTP/1.1 403 Forbidden
       
        int  line_end = input_header.indexOf(NL);
       
        if ( line_end == -1 ){
         
          throw( new IOException( "header too short" ));
        }
       
        String  first_line = input_header.substring(0,line_end);
       
        StringTokenizer  tok = new StringTokenizer(first_line, " " );
       
        tok.nextToken();
       
        int  response = Integer.parseInt( tok.nextToken());
       
        last_response  = response;
       
        last_response_retry_after_secs  = -1;
       
        String  response_str  = tok.nextToken();       
       
        if (   response == HttpURLConnection.HTTP_ACCEPTED ||
            response == HttpURLConnection.HTTP_OK ||
            response == HttpURLConnection.HTTP_PARTIAL ){
         
          byte[]  buffer     = null;
          int    buffer_pos  = 0;
          int    buffer_len  = 0;
         
          int  pos = 0;
         
          while( pos < length ){
           
            if ( buffer == null ){
             
              buffer     = listener.getBuffer();             
              buffer_pos  = listener.getBufferPosition();
              buffer_len  = listener.getBufferLength();
            }
           
            int  to_read = buffer_len - buffer_pos;
           
            int  permitted = listener.getPermittedBytes();
           
            if ( permitted < to_read ){
             
              to_read  = permitted;
            }
           
            int  len = is.read( buffer, buffer_pos, to_read );
           
            if ( len < 0 ){
             
              break;
            }
           
            listener.reportBytesRead( len );
           
            pos  += len;
           
            buffer_pos  += len;
           
            if ( buffer_pos == buffer_len ){
             
              listener.done();
             
              buffer    = null;
              buffer_pos  = 0;
            }
          }
         
          if ( pos != length ){
           
            String  log_str;
           
            if ( buffer == null ){
             
              log_str = "No buffer assigned";
             
            }else{
             
              log_str =  new String( buffer, 0, buffer_pos>64?64:buffer_pos );
            }
           
            throw( new ExternalSeedException("Connection failed: data too short - " + length + "/" + pos + " [last=" + log_str + "]" ));
          }
         
          // System.out.println( "download length: " + pos );
                   
        }else if (   response == 503 ){
         
            // webseed support for temp unavail - read the data
         
          String  data_str = "";
         
          while( true ){
           
            byte[]  buffer = new byte[1];
           
            int  len = is.read( buffer );
           
            if ( len < 0 ){
             
              break;
            }
           
            data_str += (char)buffer[0];
          }
         
          last_response_retry_after_secs = Integer.parseInt( data_str );
       
            // this gets trapped below and turned into an appropriate ExternalSeedException
         
          throw( new IOException( "Server overloaded" ));
         
        }else{
         
          ExternalSeedException  error = new ExternalSeedException("Connection failed: " + response_str );
         
          error.setPermanentFailure( true );
         
          throw( error );
        }
      }finally{
       
        is.close();
      }
     
    }catch( IOException e ){
     
      if ( con_fail_is_perm_fail && !connected ){
       
        ExternalSeedException  error = new ExternalSeedException("Connection failed: " + e.getMessage());
       
        error.setPermanentFailure( true );
       
        throw( error );

      }else{
       
        String outcome =  "Connection failed: " + Debug.getNestedExceptionMessage( e );

        if ( last_response_retry_after_secs >= 0 ){
                   
          outcome += ", Retry-After: " + last_response_retry_after_secs + " seconds";
              }

        throw( new ExternalSeedException( outcome, e ));
      }
    }catch( Throwable e ){
           
      if ( e instanceof ExternalSeedException ){
       
        throw((ExternalSeedException)e);
      }
     
      throw( new ExternalSeedException("Connection failed", e ));
     
    }finally{
     
      if ( socket != null ){
       
        try{
          socket.close();
         
        }catch( Throwable e ){
        }
      }
    }
  }
 
  public void
  deactivate()
  { 
  }
 
  public PasswordAuthentication
  getAuthentication(
    String    realm,
    URL      tracker )
  {
    return( null );
  }
 
  public void
  setAuthenticationOutcome(
    String    realm,
    URL      tracker,
    boolean    success )
  {
  }
 
  public void
  clearPasswords()
  {
  }
 
  public int
  getLastResponse()
  {
    return( last_response );
  }
 
  public int
  getLast503RetrySecs()
  {
    return( last_response_retry_after_secs );
  }
 
  public static void
  main(
    String[]    args )
  {
    try{
      String  url_str = "";
     
      ExternalSeedHTTPDownloader downloader =
   
        new ExternalSeedHTTPDownloaderRange(
            new URL( url_str ),
            "Azureus" );
       
      downloader.downloadRange(
        0, 1,
        new ExternalSeedHTTPDownloaderListener()
        {
          private int  position;
         
          public byte[]
              getBuffer()
             
                throws ExternalSeedException
              {
            return( new byte[1024] );
              }
             
              public void
              setBufferPosition(
                int  _position )
              {
                position = _position;
              }
             
              public int
              getBufferPosition()
              {
                return( position );
              }
             
              public int
              getBufferLength()
              {
                return( 1024 );
              }
             
              public int
              getPermittedBytes()
             
                throws ExternalSeedException
              {
                return( 1024 );
              }
             
              public int
                 getPermittedTime()
              {
                return( Integer.MAX_VALUE );
              }
             
              public void
              reportBytesRead(
                int    num )
              {
                System.out.println( "read " + num );
              }
             
              public boolean
              isCancelled()
              {
                return false;
              }
             
              public void
              done()
              {
                System.out.println( "done" );
              }
        },
        true );
     
    }catch( Throwable e ){
     
      e.printStackTrace();
    }
  }
}
TOP

Related Classes of com.aelitis.azureus.plugins.extseed.util.ExternalSeedHTTPDownloaderRange

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.