# URLConnection unter 1.7 macht Probleme



## windl (31. Mai 2012)

Hi NG,

wenn ich versuche einen Shoutcast-Stream mit URLConnection zu öffnen bekomme ich unter JAVA 1.7 die Fehlermeldung "Invalid Stream Header".  Dieses Verhalten tritt unter Java 1.6 nicht auf - da klappt alles wunderbar ???:L
Google hat mir mitgeteilt, dass in dieser Version der Header untersucht wird. Dieser muss unbedingt mit "HTTP" beginnen. Da ich aber einen Shoutcast-Stream einlade, beginnt dieser nicht mit diesem Flag sondern ich empfange einen Stream welchen ich direkt in einen Player übergeben kann. 

Als Work-Around wurde mir mitgeteilt, wenn dieser Fehler auftritt den ErrorStream auszulesen. Dieser ist aber NULL.

Kennt einer von Euch eine Möglichkeit den InputStream zu empfangen?

Danke
Uwe


----------



## HoaX (1. Jun 2012)

Gib doch mal ein paar Zeilen Code zum Ausprobieren...


----------



## windl (1. Jun 2012)

Hallo,

also hier ein paar Zeilen Code. Bitte - die angegebene URL ist eine Shoutcast-Url und kann sich ändern!
Ich betone noch einmal unter Java 1.6 läuft es. Allerdings gibt es in Java 1.7 einige wunderbare Erweiterungen zu 1.6 auf die ich nicht mehr verzichten möchte.


```
URL tUrl = new URL("http://scfire-mtc-aa06.stream.aol.com:80/stream/1060");
URLConnection  con = (URLConnection)tUrl.openConnection();
con.setReadTimeout(1000);
InputStream stream = con.getInputStream();
```

Darauf bekomme ich die folgende Fehlermeldung:

```
java.io.IOException: Invalid Http response
at sun.net.[url]www.protocol.http.HttpURLConnection.getInputStream(Unknown[/url] Source)
```

Danke 
Uwe


----------



## windl (1. Jun 2012)

Problem gelöst !


----------



## mfernau (1. Jun 2012)

Eine kurze Info darüber wie Du das Problem gelöst hast würde einem Suchenden die erneute Frage zu diesem Thema ersparen ;-)


----------



## windl (1. Jun 2012)

Folgende Lösung habe ich für mein Problem gefunden.
Bitte - das ist nur eine "Quick and dirty" Implementierung.
Aus diesem Ansatz heraus werde ich noch eine saubere Klasse entwickeln, die mit Proxy und TimeOut umgehen kann.


```
try{
			URL url = new URI("http://scfire-mtc-aa06.stream.aol.com:80/stream/1060").toURL();
			System.out.println(url.getPath());
		
			Socket socket = new Socket(url.getHost(),url.getPort());
			
			PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))); 
			out.println("GET "+url.getPath()+" HTTP/1.0"); 
			out.println(); 
			out.flush(); 

			BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

			String inputLine; 
			int count = 0; 

			while ((inputLine = in.readLine()) != null) { 
			count++; 
			System.out.println(count); 
			System.out.println(inputLine); 
			} 

			in.close(); 
}catch(Exception error){
	error.printStackTrace();
}
```

Jetzt bekommme ich wieder sauber den Shoutcast-Stream welchen ich meinem Player übergeben kann.


----------



## nillehammer (1. Jun 2012)

Ich habe diesen Thread gestern bereits verfolgt, aber nichts geschrieben, weil ich nichts Sinnvolles beitragen konnte. Danke für das Posten Deiner Lösung. Hat mich auch interessiert. Soo Q&D finde ich die garnicht. Eine kleiner Tipp nur:

```
URL url = new URI("http://scfire-mtc-aa06.stream.aol.com:80/stream/1060").toURL();
```
Du brauchst nicht in URL zu konvertieren. Die ganzen Methoden, die Du später benutzt (getPort etc.) gibt es auch direkt in URI.


----------



## HoaX (1. Jun 2012)

Wenn man sich den Response vom Server anschaut, dann ist es durchaus berechtigt dass URL meckert. Das ist nichtmal HTTP/1.0 sondern irgendwas davor.


----------



## windl (1. Jun 2012)

Ja, es ist ein Shoutcast-Stream mit einem ICY-Header.

ICY 200 OK
icy-notice1: <BR>This stream requires <a href="http://www.winamp.com/">Winamp</a><BR>
icy-notice2: Firehose Ultravox/SHOUTcast Relay Server/Linux v2.6.0<BR>
icy-name: #MUSIK.GOLDIES - #Musik Internetradio, Webradio, Online Radio - RauteMusik.FM - 24H OLDIES CLASSIC ROCK 60S 70S 80S POP AND MORE!
icy-genre: Decades Oldies 80s 70s 60s
icy-url: #Musik Internetradio, Webradio, Online Radio - RauteMusik.FM
content-type: audio/mpeg
icy-pub: 1
icy-br: 128


----------



## windl (1. Jun 2012)

Auch wenn es nicht mit einem HTTP anfängt - es ist und bleibt eine URL-Adresse. 
Es sollte trotzdem möglich sein, einen solchen Stream mit Java-Boardmitteln zu laden. 
Ich will keine rhetorische Frage aufwerfen aber der Stream ist via URL zu erreichen aber in JAVA 1.7 nicht mehr mit Java-Boardmitteln zu erreichen!
Ist diese zusätzliche Implementierung nicht etwas kurz gedacht und der Blick über den Tellerrand wurde nicht getan?

Ich bedanke mich für die tollen Anregungen!
Super Forum
Uwe


----------



## HoaX (2. Jun 2012)

windl hat gesagt.:


> Auch wenn es nicht mit einem HTTP anfängt - es ist und bleibt eine URL-Adresse.
> Es sollte trotzdem möglich sein, einen solchen Stream mit Java-Boardmitteln zu laden.
> Ich will keine rhetorische Frage aufwerfen aber der Stream ist via URL zu erreichen aber in JAVA 1.7 nicht mehr mit Java-Boardmitteln zu erreichen!
> Ist diese zusätzliche Implementierung nicht etwas kurz gedacht und der Blick über den Tellerrand wurde nicht getan?
> ...



Ich denke du hast eine falsche Definition von URL. Auch mailto://adler@horst.invalid?subject=Schwul ist eine gültige URL. Dennoch wird URL#openConnection() nicht funktionieren, da es auch keinen Sinn macht.
Bei deiner URL steht vorne, als Protokoll, http://. Entsprechend wird auch eine HTTP-Antwort erwartet und nicht Shoutcast.

URL (Java Platform SE 6) sagt auch welche Protokolle unterstützt werden. Wenn Shoutcast trotzdem geht dann ist das halt Zufall/Toleranz, dennoch darf man sich eben nicht darauf verlassen. Auch sagt dir der Link wir du deinen eingenen Protokollhandler registrieren kannst, so dass du z.B. shoutcast://... als URL verwenden kannst.


----------



## Empire Phoenix (3. Jun 2012)

Warum nicht einfach nen TCP connection manuall aufbauen und von dort lesen? 
Benötigten request (von wgen url) noch vorher manuell rausschieben.

-> Keine abhängigkeit von bug verhalten der jvm
-> sauber
-> zukunftsicher


----------



## HoaX (3. Jun 2012)

Empire Phoenix hat gesagt.:


> Warum nicht einfach nen TCP connection manuall aufbauen und von dort lesen?
> Benötigten request (von wgen url) noch vorher manuell rausschieben.
> 
> -> Keine abhängigkeit von bug verhalten der jvm
> ...



Lies mal Post #6


----------



## windl (4. Jun 2012)

Hi NG,

Ihr habt absolut Recht, Java verhält sich richtig. In Unwissenheit zu schnell geschrieben ;o(

Trotzdem - das Problem dass man den Stream nicht mehr bekommt blieb erhalten. 
Habe jetzt eine Klasse erstellt, die für meine Belange absolut reicht. Was ich zusätzlich eingebaut habe ist ein HTTP-Proxy für eine Socketinstanz. 

Muss gestehen, ich bin kein Netzwerkspezialist in Java somit mögen sich mit Sicherheit einige Fehler im Source tummeln.

Es wäre schön, wenn ich darauf konstruktive Kritik erhalten würde - bzw wenn sich der Eine oder Andere finden würde der den Source evtl weiter ausbauen möchte.


```
package mediaGate.generalFrontend.streamConnection;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;

public class MediaGateURLConnection {

	//hält die URL, mit der man sich verbinden möchte
	private URI localURL = null;
	//hält die Socketverbindung
	private Socket socket	= null;
	//ConnectionTimout
	private int defaultConnectTimeout = -1;
	
	private HTTPSocketTunnel sTunnel = null;
	
	/**Übergeben einer URL*/
	public MediaGateURLConnection(String url){
		this(url,"",-1);
	}
	
	/**Übergeben einer URL und eines Proxy*/
	public MediaGateURLConnection(String url,String host, int port){
		this(url,host,port,0);
	}
	
	/**Übergeben einer URL und eines Proxy und einer connection-timeout
	 * Der Proxy kann auch "" und der Port -1 sein, wenn man eine timeout mitgeben will */
	public MediaGateURLConnection(String url,String host,int port,int timeout){
		try{
		
			//ConnectionProperties einlesen
			//Die Java-Defaulteinstellungen werden ausgelesen
			readConnectionProperties();
			
			if(port>-1){
				//Implementierung mit PROXY
				sTunnel = new HTTPSocketTunnel(host,port,timeout);
				sTunnel.connectURL(url);
				
			} else {
				//Implementierung ohne PROXY
				//Ab hier wird die Verbindung selber erstellt.
				localURL = new URI(url);
				
				//Socket erstellen
				socket = createSocket(localURL.getHost(), localURL.getPort(), timeout);
		       
				//Sollte ein Unterpfad in der URL vorhanden sein, dann in
				//diesen Pfad wechseln.
				if(!localURL.getPath().equals("")){
					//Unteren Pfad abfragen
					changeServerPath(new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))),localURL.getPath());
				}
			}
		}catch(Exception error){
			error.printStackTrace();
		}
	}

	
	/** gibt den InputStream als BufferedInputStream der Socket zurück oder NULL bei einem Fehler
	 *  BufferedInputstream deswegen, da für den Shoutcast-Stream ein Stream benötigt wird, der das Flag 
	 *  markSupported auf TRUE hat. */
	public BufferedInputStream getInputStream(){
		try{
			
			if(sTunnel != null){
				return new BufferedInputStream(sTunnel.getInputStream());
			}
			if(socket != null){
				return new BufferedInputStream(socket.getInputStream());
			}
		}catch(Exception error){}
		return null;
	}
	
	/**Beendet die vorhandene Verbindung*/
	public void closeConnection(){
		try{
			if(sTunnel != null){
				sTunnel.closeServer();
			} else {
				socket.close();
			}
		}catch(Exception error){
			error.printStackTrace();
		}
	}
	
	/**Die benötigten Javastandards auslesen*/
	private void readConnectionProperties(){
		
		int vals[] = {0, 0};
		String encs[] = { null };
		
		vals[0] = Integer.getInteger("sun.net.client.defaultReadTimeout", 0).intValue();
		vals[1] = Integer.getInteger("sun.net.client.defaultConnectTimeout", 0).intValue();
		encs[0] = System.getProperty("file.encoding", "ISO8859_1");
		
		defaultConnectTimeout = vals[1] == 0?-1:vals[1];
	
	}
	
	
	private class HTTPSocketTunnel {

		//hält die Serversocket
		private Socket sSocket = null;
		//hält den outputStream um darüber die URL via HTTP-Proxy anzufordern
		private PrintWriter outputStream = null;
		
		
		private HTTPSocketTunnel(String host,int port,int timeout){
			try{
				sSocket = createSocket(host,port,timeout);
				sSocket.setSoTimeout(0);
				outputStream = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sSocket.getOutputStream()))); 
				
			}catch(Exception error){}
		}
		
		/**Diese Funktion wechselt im Server zur entsprechenden URL*/
		private void connectURL(String url){
			changeServerPath(outputStream,url);
		}

		/**gibt den InputStream zur URL zurück*/
		private InputStream getInputStream(){
			try{
				return sSocket.getInputStream();
			}catch(Exception error){}
			
			return null;
		}
		
		/**Der Server wird geschlossen*/
		private void closeServer(){
			try{
				sSocket.close();
				outputStream = null;
			}catch(Exception error){}
		}
		
	}
	
	
	//#####################################################################################
	//## Hilfefunktion wie Socket erstellen unter Berücksichtigung der Timeout
	//##
	//## Serverpfad wechseln
	//#####################################################################################
	private Socket createSocket(String url,int port, int timeout){
		try{
			Socket socket = new Socket();
			if (timeout >= 0) {
	            socket.connect(new InetSocketAddress(url, port), timeout);
	        } else {
	            if (defaultConnectTimeout > 0) {
	                socket.connect(new InetSocketAddress(url, port), defaultConnectTimeout);
	            } else {
	                socket.connect(new InetSocketAddress(url, port));
	            }
	        }
			return socket;
		}catch(Exception error){
			error.printStackTrace();
		}
		return null;
	}
	
	private void changeServerPath(PrintWriter out,String urlPath){
		out.println("GET "+urlPath+" HTTP/1.0"); 
		out.println(); 
		out.flush(); 
	}
	//#####################################################################################
	//## Ende der Hilfefunktionen
	//#####################################################################################
}
```


----------



## windl (5. Jun 2012)

Hi NG,

nun muss ich doch noch ein UPDATE nachschieben. Verbunden mit einer Frage!

Ich hatte folgendes Problem, dass wenn ich den INPUTSTREAM an JLAYER (javazoom) übergeben habe, habe ich die Lied-Informationen nicht erhalten. Etwas musste ich im Package mp3spi1.9.5 umbauen dass es klappt und ich musste meine Klasse ertüchtigen dass sie mit setRequestProperty() umgehen kann. 
Beides habe ich nun geschafft und ich bekomme die Titelinformationen wieder angezeigt.

Nun zu meiner Frage. Wie kann ich denn in diese Klasse die Funktion* getHeaderField(String )* implementieren?


```
package mediaGate.generalFrontend.streamConnection;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
import java.util.ArrayList;

public class MediaGateURLConnection {

	//hält die URL, mit der man sich verbinden möchte
	private URI localURL = null;
	//hält die Socketverbindung
	private Socket socket	= null;
	//ConnectionTimout
	private int defaultConnectTimeout = -1;
	/**hält eine Insanz zum HTTP-ProxyTunnel*/
	private HTTPSocketTunnel sTunnel = null;
	/**hält den PrintWriter*/
	private PrintWriter outWriter = null;
	/**Eine Liste für UserProperties die beim GET mitgegeben werden können*/
	private ArrayList<String> propertyList = null;
	
	private String url 		= "";
	private String host		= "";
	private int port		= -1;
	private	int timeout		= -1;
	
	
	
	/**Übergeben einer URL*/
	public MediaGateURLConnection(String url){
		this(url,"",-1);
	}
	
	/**Übergeben einer URL und eines Proxy*/
	public MediaGateURLConnection(String url,String host, int port){
		this(url,host,port,0);
	}
	
	/**Übergeben einer URL und eines Proxy und einer connection-timeout
	 * Der Proxy kann auch "" und der Port -1 sein, wenn man eine timeout mitgeben will */
	public MediaGateURLConnection(String url,String host,int port,int timeout){
		this.url 		= url;
		this.host 		= host;
		this.port 		= port;
		this.timeout 	= timeout;
	}

	
	/** gibt den InputStream als BufferedInputStream der Socket zurück oder NULL bei einem Fehler
	 *  BufferedInputstream deswegen, da für den Shoutcast-Stream ein Stream benötigt wird, der das Flag 
	 *  markSupported auf TRUE hat. */
	public InputStream getInputStream(){
		try{
			
			try{
				
				//ConnectionProperties einlesen
				//Die Java-Defaulteinstellungen werden ausgelesen
				readConnectionProperties();
				
				if(port>-1){
					//Implementierung mit PROXY
					sTunnel = new HTTPSocketTunnel(host,port,timeout);
					sTunnel.connectURL(url);
					
				} else {
					//Implementierung ohne PROXY
					//Ab hier wird die Verbindung selber erstellt.
					localURL = new URI(url);
					
					//Socket erstellen
					socket = createSocket(localURL.getHost(), localURL.getPort(), timeout);
			       
					//Sollte ein Unterpfad in der URL vorhanden sein, dann in
					//diesen Pfad wechseln.
					if(!localURL.getPath().equals("")){
						//Unteren Pfad abfragen
						outWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
						changeServerPath(localURL.getPath());
					} else {
						//Der Pfad ist leer aber trotzdem kann etwas in den Requestproperties stehen die noch gesendet werden müssen
						if(propertyList!=null){
							changeServerPath(localURL.getHost());
						}
					}
				}
			}catch(Exception error){
				error.printStackTrace();
			}
			
			
			if(sTunnel != null){
				return new BufferedInputStream(sTunnel.getInputStream());
			}
			if(socket != null){
				return new BufferedInputStream(socket.getInputStream());
			}
		}catch(Exception error){}
		return null;
	}
	
	/**Beendet die vorhandene Verbindung*/
	public void closeConnection(){
		try{
			if(sTunnel != null){
				sTunnel.closeServer();
			} else {
				socket.close();
			}
		}catch(Exception error){
			error.printStackTrace();
		}
	}
	
	/**Die benötigten Javastandards auslesen*/
	private void readConnectionProperties(){
		
		int vals[] = {0, 0};
		String encs[] = { null };
		
		vals[0] = Integer.getInteger("sun.net.client.defaultReadTimeout", 0).intValue();
		vals[1] = Integer.getInteger("sun.net.client.defaultConnectTimeout", 0).intValue();
		encs[0] = System.getProperty("file.encoding", "ISO8859_1");
		
		defaultConnectTimeout = vals[1] == 0?-1:vals[1];
	
	}
	
	
	private class HTTPSocketTunnel {

		//hält die Serversocket
		private Socket sSocket = null;
		
		private HTTPSocketTunnel(String host,int port,int timeout){
			try{
				sSocket = createSocket(host,port,timeout);
				sSocket.setSoTimeout(0);
				outWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sSocket.getOutputStream()))); 
				
			}catch(Exception error){}
		}
		
		/**Diese Funktion wechselt im Server zur entsprechenden URL*/
		private void connectURL(String url){
			changeServerPath(url);
		}

		/**gibt den InputStream zur URL zurück*/
		private InputStream getInputStream(){
			try{
				return sSocket.getInputStream();
			}catch(Exception error){}
			
			return null;
		}
		
		/**Der Server wird geschlossen*/
		private void closeServer(){
			try{
				sSocket.close();
				outWriter.close();
				outWriter = null;
			}catch(Exception error){}
		}
		
	}
	
	/** Es können nun beim GET auch noch USER-Informationen mitgegeben werden!
	 *  Beispiel hierfür ist setRequestProperty("Icy-Metadata", "1"); für den ShoutcastStream 
	 **/
	public void setRequestProperty(String property,String value){
		if(propertyList == null){
			propertyList = new ArrayList<String>();
		}
		propertyList.add(property+": "+value);
	}
	
	//#####################################################################################
	//## Hilfefunktion wie Socket erstellen unter Berücksichtigung der Timeout
	//##
	//## Serverpfad wechseln
	//#####################################################################################
	private Socket createSocket(String url,int port, int timeout){
		try{
			Socket socket = new Socket();
			if (timeout >= 0) {
	            socket.connect(new InetSocketAddress(url, port), timeout);
	        } else {
	            if (defaultConnectTimeout > 0) {
	                socket.connect(new InetSocketAddress(url, port), defaultConnectTimeout);
	            } else {
	                socket.connect(new InetSocketAddress(url, port));
	            }
	        }
			return socket;
		}catch(Exception error){
			error.printStackTrace();
		}
		return null;
	}
	
	private void changeServerPath(String urlPath){
		outWriter.println("GET "+urlPath+" HTTP/1.0"); 
		//Überprüfen ob etwas in den Properties steht
		//und baut diese Informationen noch mit ein
		if(propertyList != null){
			for(String line:propertyList){
				outWriter.println(line);
			}
		}
		outWriter.println(); 
		outWriter.flush(); 
	}
	
	//#####################################################################################
	//## Ende der Hilfefunktionen
	//#####################################################################################
}
```


----------

