/* * 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]; if ( is.read( buffer ) <= 0 ){ throw( new IOException( "unexpected end of stream" )); } 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 == null ){ throw( new IOException( "no method supplied" )); }else 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 ); } }