int last_pos = 0;
int line_num = 0;
String target_str = null;
DiskManagerFileInfo target_file = null;
long file_offset = 0;
List<long[]> ranges = new ArrayList<long[]>();
boolean keep_alive = false;
for (int i=1;i<chars.length;i++){
if ( chars[i-1] == '\r' && chars[i] == '\n' ){
String line = new String( chars, last_pos, i - last_pos ).trim();
last_pos = i;
line_num++;
// System.out.println( "line " + line_num + " -> " + line );
if ( line_num == 1 ){
line = line.substring( line.indexOf( "files/" ) + 6 );
int hash_end = line.indexOf( "/" );
final byte[] old_hash = control.getHash();
final byte[] new_hash = URLDecoder.decode(line.substring(0, hash_end), "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(
HTTPNetworkConnectionFile.this,
old_hash, new_hash, header );
}
});
return;
}
line = line.substring( hash_end + 1 );
line = line.substring( 0, line.lastIndexOf( ' ' ));
String file = line;
if ( to_torrent.isSimpleTorrent()){
// optimise for simple torrents. also support the case where
// client has the hash but doesn't know the file name
target_file = dm.getFiles()[0];
}else{
target_str = file;
StringTokenizer tok = new StringTokenizer( file, "/" );
List<byte[]> bits = new ArrayList<byte[]>();
while( tok.hasMoreTokens()){
bits.add( URLDecoder.decode(tok.nextToken(), "ISO-8859-1").getBytes( "ISO-8859-1" ));
}
// latest spec has torrent file name encoded first for non-simple torrents
// remove it if we find it so we have some backward compat
if ( !to_torrent.isSimpleTorrent() && bits.size() > 1 ){
if ( Arrays.equals( to_torrent.getName(), (byte[])bits.get(0))){
bits.remove(0);
}
}
DiskManagerFileInfo[] files = dm.getFiles();
file_offset = 0;
for (int j=0;j<files.length;j++){
TOTorrentFile torrent_file = files[j].getTorrentFile();
byte[][] comps = torrent_file.getPathComponents();
if ( comps.length == bits.size()){
boolean match = true;
for (int k=0;k<comps.length;k++){
if ( !Arrays.equals( comps[k], (byte[])bits.get(k))){
match = false;
break;
}
}
if ( match ){
target_file = files[j];
break;
}
}
file_offset += torrent_file.getLength();
}
}
}else{
line = line.toLowerCase( MessageText.LOCALE_ENGLISH );
if ( line.startsWith( "range" ) && target_file != null ){
line = line.substring(5).trim();
if ( line.startsWith(":" )){
String range_str = line.substring(1).trim();
if ( range_str.startsWith( "bytes=" )){
long file_length = target_file.getLength();
StringTokenizer tok2 = new StringTokenizer( range_str.substring( 6 ), "," );
while( tok2.hasMoreTokens()){
String range = tok2.nextToken();
try{
int pos = range.indexOf('-');
if ( pos != -1 ){
String lhs = range.substring( 0,pos);
String rhs = range.substring(pos+1);
long start;
long end;
if ( lhs.length() == 0 ){
// -222 is last 222 bytes of file
end = file_length - 1;
start = file_length - Long.parseLong( rhs );
}else if ( rhs.length() == 0 ){
end = file_length - 1;
start = Long.parseLong( lhs );
}else{
start = Long.parseLong( lhs );
end = Long.parseLong( rhs );
}
ranges.add( new long[]{ start, end });
}
}catch( Throwable e ){
}
}
}
if ( ranges.size() == 0 ){
log( "Invalid range specification: '" + line + "'" );
sendAndClose( getManager().getRangeNotSatisfiable());
return;
}
}
}else if ( line.indexOf( "keep-alive" ) != -1 ){
keep_alive = true;
}
}
}
}
if ( target_file == null ){
log( "Failed to find file '" + target_str + "'" );
sendAndClose( getManager().getNotFound());
return;
}
try{
String name = target_file.getFile( true ).getName();
int pos = name.lastIndexOf( "." );
if ( pos != -1 ){
setContentType( HTTPUtils.guessContentTypeFromFileType( name.substring( pos+1 )));
}
}catch( Throwable e ){
}
long file_length = target_file.getLength();
boolean partial_content = ranges.size() > 0;
if ( !partial_content ){