/*
* Created on 4 Oct 2006
* Created by Paul Gardner
* 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 63.529,40 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package com.aelitis.azureus.core.networkmanager.impl.http;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.peer.impl.PEPeerControl;
import org.gudy.azureus2.core3.peer.impl.PEPeerTransport;
import org.gudy.azureus2.core3.util.Debug;
import com.aelitis.azureus.core.networkmanager.NetworkConnection;
public class
HTTPNetworkConnectionWebSeed
extends HTTPNetworkConnection
{
private boolean switching;
protected
HTTPNetworkConnectionWebSeed(
HTTPNetworkManager _manager,
NetworkConnection _connection,
PEPeerTransport _peer )
{
super( _manager, _connection, _peer );
}
protected void
decodeHeader(
final HTTPMessageDecoder decoder,
final String header )
throws IOException
{
if ( switching ){
Debug.out( "new header received while paused" );
throw( new IOException( "Bork" ));
}
if ( !isSeed()){
return;
}
PEPeerControl control = getPeerControl();
try{
int pos = header.indexOf( NL );
String line = header.substring(4,pos);
pos = line.lastIndexOf( ' ' );
String url = line.substring( 0, pos ).trim();
pos = url.indexOf( '?' );
if ( pos != -1 ){
url = url.substring( pos+1 );
}
StringTokenizer tok = new StringTokenizer( url, "&" );
int piece = -1;
List ranges = new ArrayList();
while( tok.hasMoreElements()){
String token = tok.nextToken();
pos = token.indexOf('=');
if ( pos != -1 ){
String lhs = token.substring(0,pos).toLowerCase( MessageText.LOCALE_ENGLISH );
String rhs = token.substring(pos+1);
if ( lhs.equals( "info_hash" )){
final byte[] old_hash = control.getHash();
final byte[] new_hash = URLDecoder.decode( rhs, "ISO-8859-1" ).getBytes( "ISO-8859-1" );
if ( !Arrays.equals( new_hash, old_hash )){
switching = true;
decoder.pauseInternally();
flushRequests(
new flushListener()
{
private boolean triggered;
public void
flushed()
{
synchronized( this ){
if ( triggered ){
return;
}
triggered = true;
}
getManager().reRoute(
HTTPNetworkConnectionWebSeed.this,
old_hash, new_hash, header );
}
});
return;
}
}else if ( lhs.equals( "piece" )){
try{
piece = Integer.parseInt( rhs );
}catch( Throwable e ){
throw( new IOException( "Invalid piece number '" + rhs +"'" ));
}
}else if ( lhs.equals( "ranges" )){
StringTokenizer range_tok = new StringTokenizer( rhs, "," );
while( range_tok.hasMoreTokens()){
String range = range_tok.nextToken();
int sep = range.indexOf( '-' );
if ( sep == -1 ){
throw( new IOException( "Invalid range specification '" + rhs + "'" ));
}
try{
ranges.add(
new int[]{
Integer.parseInt( range.substring(0,sep)),
Integer.parseInt( range.substring( sep+1 ))});
}catch( Throwable e ){
throw( new IOException( "Invalid range specification '" + rhs + "'" ));
}
}
}
}
}
if ( piece == -1 ){
throw( new IOException( "Piece number not specified" ));
}
boolean keep_alive = header.toLowerCase( MessageText.LOCALE_ENGLISH ).indexOf( "keep-alive" ) != -1;
int this_piece_size = control.getPieceLength( piece );
if ( ranges.size() == 0 ){
ranges.add( new int[]{ 0, this_piece_size-1});
}
long[] offsets = new long[ranges.size()];
long[] lengths = new long[ranges.size()];
long piece_offset = piece * control.getPieceLength(0);
for (int i=0;i<ranges.size();i++){
int[] range = (int[])ranges.get(i);
int start = range[0];
int end = range[1];
if ( start < 0 || start >= this_piece_size ||
end < 0 || end >= this_piece_size ||
start > end ){
throw( new IOException( "Invalid range specification '" + start + "-" + end + "'" ));
}
offsets[i] = piece_offset + start;
lengths[i] = ( end - start ) + 1;
}
addRequest( new httpRequest( offsets, lengths, 0, false, keep_alive ));
}catch( Throwable e ){
Debug.outNoStack( "Decode of '" + (header.length()>128?(header.substring(0,128) + "..."):header) + "' - " + Debug.getNestedExceptionMessageAndStack(e));
if ( e instanceof IOException ){
throw((IOException)e);
}else{
throw( new IOException( "Decode failed: " + Debug.getNestedExceptionMessage(e)));
}
}
}
}