/*
* Created on Feb 9, 2009
* Created by Paul Gardner
*
* Copyright 2009 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.devices.impl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.util.*;
public class
TranscodePipeFileSource
extends TranscodePipe
{
private static final String NL = "\r\n";
private File source_file;
private RandomAccessFile raf;
private int raf_count;
protected
TranscodePipeFileSource(
File _source_file,
errorListener _error_listener )
throws IOException
{
super( _error_listener );
source_file = _source_file;
}
protected void
handleSocket(
Socket socket )
{
synchronized( this ){
if ( destroyed ){
try{
socket.close();
}catch( Throwable e ){
}
return;
}
sockets.add( socket );
}
try{
String command = null;
Map<String,String> headers = new HashMap<String, String>();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
while( true ){
String line = "";
while( !line.endsWith( NL )){
byte[] buffer = new byte[1];
is.read( buffer );
line += new String( buffer );
}
line = line.trim();
if ( line.length() == 0 ){
break;
}
if ( command == null ){
command = line;
}else{
int pos = line.indexOf(':');
if ( pos == -1 ){
return;
}
String lhs = line.substring(0,pos).trim().toLowerCase();
String rhs = line.substring(pos+1).trim();
headers.put( lhs, rhs );
}
}
boolean head = false;
//System.out.println( command + ": " + headers );
if ( command.startsWith( "GET " )){
}else if ( command.startsWith( "HEAD " )){
head = true;
}else{
throw( new IOException( "unsupported method '" + command + "'" ));
}
long file_length = source_file.length();
if ( head ){
write( os, "HTTP/1.1 200 OK" + NL );
write( os, "Server: Azureus Media Server 1.0" + NL );
write( os, "Accept-Ranges: bytes" + NL );
write( os, "Content-Length: " + file_length + NL );
write( os, "Content-Range: 0-" + (file_length-1) + "/" + file_length + NL );
os.flush();
}else{
String ranges = (String)headers.get( "range" );
long request_start = 0;
long request_length = 0;
boolean request_ok = false;
if ( ranges == null ){
write( os, "HTTP/1.1 200 OK" + NL );
write( os, "Server: Azureus Media Server 1.0" + NL );
write( os, "Connection: close" + NL );
write( os, "Accept-Ranges: bytes" + NL );
write( os, "Content-Range: 0-" + (file_length-1) + "/" + file_length + NL );
write( os, "Content-Length: " + file_length + NL + NL );
request_length = file_length;
request_ok = true;
}else{
ranges = ranges.toLowerCase();
if ( !ranges.startsWith("bytes=")){
throw( new IOException( "invalid range: " + ranges ));
}
ranges = ranges.substring( 6 );
StringTokenizer tok = new StringTokenizer( ranges, "," );
if ( tok.countTokens() != 1 ){
throw( new IOException( "invalid range - only single supported: " + ranges ));
}
String range = tok.nextToken();
int pos = range.indexOf('-');
long start;
long end;
if ( pos < range.length()-1 ){
end = Long.parseLong( range.substring(pos+1));
}else{
end = file_length-1;
}
if ( pos > 0 ){
start = Long.parseLong( range.substring(0,pos));
}else{
// -500 = last 500 bytes of file
start = file_length-end;
end = file_length-1;
}
request_length = ( end - start ) + 1;
// prevent seeking too far
if ( request_length < 0 ){
write( os, "HTTP/1.1 416 Requested Range Not Satisfiable" + NL + NL );
}else{
request_start = start;
write( os, "HTTP/1.1 206 Partial content" + NL );
write( os, "Server: Azureus Media Server 1.0" + NL );
write( os, "Connection: close" + NL );
write( os, "Content-Range: bytes " + start + "-" + end + "/" + file_length + NL );
write( os, "Content-Length: " + request_length + NL + NL );
request_ok = true;
}
}
os.flush();
if ( request_ok ){
handleRAF( os, request_start, request_length );
}
}
synchronized( this ){
if ( destroyed ){
try{
socket.close();
}catch( Throwable e ){
}
try{
is.close();
}catch( Throwable e ){
}
sockets.remove( socket );
return;
}
}
}catch( Throwable e ){
try{
socket.close();
}catch( Throwable f ){
}
synchronized( this ){
sockets.remove( socket );
}
}
}
protected void
write(
OutputStream os,
String str )
throws IOException
{
os.write( str.getBytes());
}
@Override
protected RandomAccessFile
reserveRAF()
throws IOException
{
synchronized( this ){
if ( destroyed ){
throw( new IOException( "destroyed" ));
}
if ( raf == null ){
raf = new RandomAccessFile( source_file, "r" );
}
raf_count++;
return( raf );
}
}
@Override
protected void
releaseRAF(
RandomAccessFile _raf )
{
synchronized( this ){
raf_count--;
if ( raf_count == 0 ){
try{
raf.close();
}catch( Throwable e ){
}
raf = null;
}
}
}
protected boolean
destroy()
{
if ( super.destroy()){
if ( raf != null ){
try{
raf.close();
}catch( Throwable e ){
}
raf = null;
}
return( true );
}
return( false );
}
}