gt: 				    				return( null );
context: /*
   * Created on 2 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 com.aelitis.azureus.core.networkmanager.NetworkConnection;
  import com.aelitis.azureus.core.networkmanager.NetworkManager;
  import com.aelitis.azureus.core.networkmanager.Transport;
  import com.aelitis.azureus.core.networkmanager.impl.TransportHelper;
  import com.aelitis.azureus.core.networkmanager.impl.tcp.IncomingSocketChannelManager;
  import com.aelitis.azureus.core.peermanager.PeerManager;
  import com.aelitis.azureus.core.peermanager.PeerManagerRegistration;
  import com.aelitis.azureus.core.peermanager.PeerManagerRoutingListener;
  import com.aelitis.azureus.core.peermanager.messaging.MessageStreamDecoder;
  import com.aelitis.azureus.core.peermanager.messaging.MessageStreamEncoder;
  import com.aelitis.azureus.core.peermanager.messaging.MessageStreamFactory;
  import com.aelitis.azureus.core.stats.AzureusCoreStats;
  import com.aelitis.azureus.core.stats.AzureusCoreStatsProvider;
  import com.aelitis.azureus.core.util.CopyOnWriteList;
  import org.gudy.azureus2.core3.logging.LogEvent;
  import org.gudy.azureus2.core3.logging.LogIDs;
  import org.gudy.azureus2.core3.logging.Logger;
  import org.gudy.azureus2.core3.peer.impl.PEPeerTransport;
  import org.gudy.azureus2.core3.torrent.TOTorrentFile;
  import org.gudy.azureus2.core3.util.BEncoder;
  import org.gudy.azureus2.core3.util.Debug;
  
  import java.io.UnsupportedEncodingException;
  import java.net.InetAddress;
  import java.net.InetSocketAddress;
  import java.net.URLDecoder;
  import java.net.URLEncoder;
  import java.nio.ByteBuffer;
  import java.util.*;
  
  public class 
  HTTPNetworkManager 
  {
  	private static final String	NL			= "\r\n";
  
  	private static final LogIDs LOGID = LogIDs.NWMAN;
  
  	private static final HTTPNetworkManager instance = new HTTPNetworkManager();
  
  	public static HTTPNetworkManager getSingleton(){ return( instance ); }
  
  	
  	private final IncomingSocketChannelManager http_incoming_manager;
  
  	private long	total_requests;
  	private long	total_webseed_requests;
  	private long	total_getright_requests;
  	private long	total_invalid_requests;
  	private long	total_ok_requests;
  	
  	private CopyOnWriteList<URLHandler>	url_handlers = new CopyOnWriteList<URLHandler>();
  	
  	private 
  	HTTPNetworkManager()
  	{	
  		  Set	types = new HashSet();
  		  
  		  types.add( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_COUNT );
  		  types.add( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_OK_COUNT );
  		  types.add( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_INVALID_COUNT );
  		  types.add( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_WEBSEED_COUNT );
  		  types.add( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_GETRIGHT_COUNT );
  			
  		  AzureusCoreStats.registerProvider( 
  				  types,
  				  new AzureusCoreStatsProvider()
  				  {
  						public void
  						updateStats(
  							Set		types,
  							Map		values )
  						{
  							if ( types.contains( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_COUNT )){
  								
  								values.put( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_COUNT, new Long( total_requests ));
  							}	
  							
  							if ( types.contains( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_OK_COUNT )){
  								
  								values.put( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_OK_COUNT, new Long( total_ok_requests ));
  							}					
  
  							if ( types.contains( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_INVALID_COUNT )){
  								
  								values.put( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_INVALID_COUNT, new Long( total_invalid_requests ));
  							}					
  
  							if ( types.contains( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_WEBSEED_COUNT )){
  								
  								values.put( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_WEBSEED_COUNT, new Long( total_webseed_requests ));
  							}	
  							
  							if ( types.contains( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_GETRIGHT_COUNT )){
  								
  								values.put( AzureusCoreStats.ST_NET_HTTP_IN_REQUEST_GETRIGHT_COUNT, new Long( total_getright_requests));							}					
  
  						}
  				  });
  		/*
  		try{
  			System.out.println( "/webseed?info_hash=" + URLEncoder.encode( new String( ByteFormatter.decodeString("C9C04D96F11FB5C5ECC99D418D3575FBFC2208B0"), "ISO-8859-1"), "ISO-8859-1" ));
  			
  		}catch( Throwable e ){
  			
  			e.printStackTrace();
  		}
  		*/
  		
  		http_incoming_manager = new IncomingSocketChannelManager( "HTTP.Data.Listen.Port", "HTTP.Data.Listen.Port.Enable" );
  		
  		NetworkManager.ByteMatcher matcher =
  		   	new NetworkManager.ByteMatcher() 
  		    {
  				public int matchThisSizeOrBigger(){	return( 4 + 1 + 11 ); } // GET ' ' <url of 1> ' HTTP/1.1<cr><nl>'
  				
  		    	public int maxSize() { return 256; }	// max GET <url> size - boiler plate plus small url plus hash
  		    	public int minSize() { return 3; }		// enough to match GET
  
  		    	public Object
  		    	matches( 
  		    		TransportHelper		transport,
  		    		ByteBuffer 			to_compare, 
  		    		int 				port ) 
  		    	{
  		    		total_requests++;
  		    		
  		    		InetSocketAddress	address = transport.getAddress();
  		    		
  		    		int old_limit 		= to_compare.limit();
  		    		int old_position 	= to_compare.position();
  
  		    		boolean 	ok = false;
  		    		
  		    		try{
  			    		byte[]	head = new byte[3];
  			    		
  			    		to_compare.get( head );
  			    		
  			    			// note duplication of this in min-matches below
  			    		
  			    		if ( head[0] != 'G' || head[1] != 'E' || head[2] != 'T' ){
  			    			
  			    			return( null );
  			    		}
  			    		
  			    		byte[]	line_bytes = new byte[to_compare.remaining()];
  			    		
  			    		to_compare.get( line_bytes );
  			    		
  			    		try{
  			    				// format is GET url HTTP/1.1<NL>
  			    			
  				    		String	url = new String( line_bytes, "ISO-8859-1" );
  				    		
  				    		int	space = url.indexOf(' ');
  				    		
  				    		if ( space == -1 ){
  				    			
  				    			return( null );
  				    		}
  				    		
  				    			// note that we don't insist on a full URL here, just the start of one
  				    		
  				    		url = url.substring( space + 1 ).trim();
  				    				
  				    		if ( url.indexOf( "/index.html") != -1 ){
  				    			
  				    			ok	= true;
  				    			
  					    		return( new Object[]{ transport, getIndexPage() });
  					    		
  				    		}else if ( url.indexOf( "/ping.html") != -1 ){
  					    			
  				    				// ping is used for inbound HTTP port checking
  				    			
  				    			ok	= true;
  				    			
  						    	return( new Object[]{ transport, getPingPage( url ) });
  
  				    		}else if ( url.indexOf( "/test503.html" ) != -1 ){
  				    			
  				    			ok	= true;
  				    			
  					    		return( new Object[]{ transport, getTest503()});
  				    		}
  
  				    		String	hash_str = null;
  				    		
  				    		int	hash_pos = url.indexOf( "?info_hash=" );
  				    						    		
  				    		if ( hash_pos != -1 ){
  				    							    			
  				    			int	hash_start = hash_pos + 11;
  				    			
  				    			int	hash_end = url.indexOf( '&', hash_pos );
  				    							    			
  				    			if ( hash_end == -1 ){
  				    				
  				    					// not read the end yet
  				    				
  