UPnP ContentDirectory Browse returns null - java

I have been playing around with UPnP, to get an understanding of how it all works, before I try working with any of the APIs that are out there, or doing anything more substantial. I have been reading through the UPnP documentation, and have used that information to format the messages that I am sending. I am just working from the command line right now, and have gotten discovery messages to work without issue. Now, I'm trying to return content from a ContentDirectory Browse() request (I have also tried TransportAV GetMediaInfo() because it takes only one argument). However, no matter what I try, I am getting a Null response from the MediaServer.
public class SOAPSocket2 {
public static void main(String[] args) {
try {
String xmldata = "<?xml version=\"1.0\"?>" +
"<s:Envelope " +
"xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/ \"" +
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
"<s:Body>" +
"<u:GetMediaInfo xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">" +
"<InstanceID>0</InstanceID>" +
"</u:GetMediaInfo>" +
"</s:Body>" +
"</s:Envelope>";
//Create socket
String hostname = args[0];
int port = Integer.parseInt(args[1]);
Socket sock = new Socket(hostname, port);
//Send header
String path = args[2];
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream(),"UTF-8"));
// You can use "UTF8" for compatibility with the Microsoft virtual machine.
wr.write("POST " + path + " HTTP/1.1\r\n");
wr.write("HOST: " + hostname + ":" + port +"\r\n");
wr.write("CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n");
wr.write("SOAPACTION: \"urn:schemas-upnp-org:service:AVTransport:1#GetMediaInfo\"");
wr.write("\r\n");
//Send data
wr.write(xmldata);
wr.flush();
// Response
BufferedReader rd = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String line;
line = rd.readLine();
System.out.println(line);
while((line = rd.readLine()) != null)
System.out.println(line);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I know this isn't the most proper code, but I borrowed it from here: http://users.skynet.be/pascalbotte/rcx-ws-doc/xmlpost.htm. I figured that if I could actually get some sort of data in a response, then I could work on building it properly. I have modified it so that I pass the IP address and Port of the Media Server from the command line, as well as the path to the Control URL. However, I am getting nothing but 'null' from the Media Server. Any thoughts on what I'm doing incorrectly? Thanks

I am getting a Null response from the MediaServer
Is that a response from MediaServer? I would imagine it's just BufferedReader telling you there's nothing to return.
You have two things here you can debug (sending and receiving) but the same tools should help with both. Use wireshark or another network traffic capture tool to see the actual data that goes through the network. Wireshark will tell you if the response is sent (but you are failing to receive it properly) or if the reply never comes (implying your message is incorrect). It will also show your message as it is on the wire, making it easier to notice mistakes.
Doing the above (and pasting the messages here if you can't figure it out) is the best way to continue debugging, but I can see some problems in the code already:
SOAPACTION-line is missing "\r\n" in the end
There is no CONTENT-LENGTH header (this is required in normal cases)
These aren't even UPnP problems really, the message just isn't proper HTTP. Still, the UPnP Device Architecture document will help with problems like this.

Related

How to read an HTTP response from a server (as a web proxy) and send response to client

I am writing a web proxy and so far I can read a GET request from a client, format it, and send it to the server, I believe that I have been able to get the response back from the server, but am unsure of how to send the response to the client.
Scanner readClient = new Scanner(new InputStreamReader(client.getInputStream()));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
System.out.println("Client Request: ");
String request;
String host = "";
String path = "";
String[] parts = new String[4];
while((request = bufferedReader.readLine())!= null) {
if (request.indexOf("deflate") != -1) {
break;
}
if(request.indexOf("GET") != -1){
parts = request.split(" ");
path = parts[1];
System.out.println("THIS IS THE PATH: " + path);
}
if(request.indexOf("Host") != -1){
parts = request.split(": ");
host = parts[1];
System.out.println("THIS IS THE HOST: " + host);
}
System.out.println(request);
}
Socket server = new Socket(host, 80);
System.out.println("Successfully connected to host: " + host);
PrintWriter writeServer = new PrintWriter(new DataOutputStream(server.getOutputStream()));
InputStream readServer = server.getInputStream();
writeServer.print("GET " + path + "\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n");
writeServer.flush();
OutputStream writeClient = client.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buffer[] = new byte[1024];
for(int s; (s=readServer.read(buffer)) != -1; )
{
baos.write(buffer, 0, s);
}
byte result[] = baos.toByteArray();
System.out.println("message sent");
}
catch (Exception e) {
System.out.println("Start Exception: " + e.getMessage());
}
}
** Not sure how I am supposed to record edits made to the question, but I have changed my wording and updated my code as well as included more of it.
You just need to read and copy the input to the output, taking note of the content-length or transfer-encoding headers on the way past, and stop when you exhaust either the content-length or whatever the transfer encoding thinks is the end of the response.
What kind of errors are you trying to catch? Did some homework last term using Scanner(URL.openStream()) and for anything "not normal" that would display as an error in a browser it would throw an Exception. Here's my catch() statement with some comments, it worked for what I needed at the time.
// do we have an error?
catch (Exception ex) {
// rather than specific exceptions related to the type of
// error (network, protocol, webserver content/configuration)
// the java.net.URL.openStream(URL) seems to return
// a different message in .getMessage() that you have to
// parse to figure out what happened.
// would these messages be different in a different java/jvm implementation?
String errorMsg=ex.getMessage();
// nicer errors below
//System.out.println("Error: "+errorMsg+"\n\r");
// what makes up our URL? this lets us get the hostname
// easily as urlParts[2].
String[] urlParts=theURL.split("/");
// on DNS failure (use http://aintthere.example.com as test URL)
// Exception.getMessage() seems to return the desired hostname
if(errorMsg.indexOf(urlParts[2])==0){
System.out.println("DNS error - invalid or unknown hostname");
}
// on a 404 error (use http://www.example.com/aintthere) the
// Exception.getMessage() appears to return the URL requested.
if(errorMsg.indexOf(theURL)==0){
System.out.println("The requested URL does not exist: "+theURL);
}
// no route to host or host off line and/or denying connections
if(errorMsg.indexOf("Connection timed out")==0){
System.out.println("That host is unreachable or is not allowing connections");
}
// turns out lots of different SSL errors - invalid certs, self signed certs, mis-matched hostnames,
// all sorts of things. seems easier to parse for ".security." in the message since
// they seem to come either from java.security.cert.* or sun.security.*
if(errorMsg.indexOf(".security.")!=-1){
System.out.println("Insecure SSL connection attempt - not allowed");
}
// both 500 (Internal Server Error) and 403 (Access to Resource Forbidden)
// produce nice standard looking error messages with the error number in them, so
// we check for that. Why doesn't 404 do that?
if(errorMsg.indexOf("HTTP response code: 500")!=-1){
System.out.println("The webserver is suffering from its own issues - Internal Server Error detected");
}
if(errorMsg.indexOf("HTTP response code: 403")!=-1){
System.out.println("Access to that resource is forbidden by the webserver configuration");
}
} // end catch

ObjectOutputStream.writeBytes(String s) unexpected output values

I am using an ObjectOutputStream object os to send a String msg from a client Android app to a c++ server.
I know how my msg must be received by the server:
each char of the msg is stored in a byte array (received_msg[]). I also know the exact msg the server expects (through another c++ app).
The data I send is a string made from 1 byte array and 2 other string.
My problem:
I already used PrintWriter to send my data, but my server would always display some weird char in received_msg, at index 24 to 28.
I tried a lot of conversions to fix it, but gave up on that.
So I tried sending msg with ObjectOutputStream.
With the client using ObjectOutputStream.writeBytes(), the server shows almost the right received message. Almost because there are characters that are added at the beginning.
Something like that :
In the server received_msg:
index 0: ┐
index 1: i
index 2: ''
index 3: |
index 4: I //beginning of the message I actually wanted to send
index 5: S //every char following index 4 is good.
while I expected and sent nothing before 'I''S'.
The message I send begins like that : ISOXXXXX
So I was wondering if there were any ways to retrieve the REAL output of ObjectOutputStream.writeBytes. I know that it's Output, not Input, still that would help me understand how it adds the weird header.
Thanks in advance for your suggestion
My send function
private void send(String o) {
System.out.println("socket");
try {
this.socket = new Socket(serverIP, portNumber);
os = new ObjectOutputStream(socket.getOutputStream());
//OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
//InputStreamReader in = new InputStreamReader(socket.getInputStream());
// PrintWriter pw = new PrintWriter(out, true);
System.out.println("Connected to server : " + this.socket.getInetAddress() + " on port " + this.socket.getPort());
System.out.println("from local address: " + this.socket.getLocalAddress() + " and port: " + this.socket.getLocalPort());
System.out.println("02. -> Sending an object...");
ArrayList<String> tempoStr = StringToByteArray(o);
String msg="";
for(String inStr :tempoStr)
msg+=inStr;
System.out.println("the message I ACTUALLY send is\n"+msg); //the result in console is EXACTLY the message I expect.
os.writeBytes(msg); //then when I check on the server: unexpected additionnal chars at the beginning.
os.flush();
// pw.write(msg);
//pw.flush();
System.out.println("send success");
} catch (IOException e) {
e.printStackTrace();
System.out.println("XX. Exception Occurred on Sending:" + e.toString() +"\n"+ e.getCause());
System.out.println("Socket creation failure or error on sending.");
}
}
PS: I cannot change the server code.
Do not use ObjectOutputStream (java only). One might use DataOutputStream, but here it seems you want something simple.
byte[] a = ...
String b = ...
OutputStream out = ...
out.write(a);
out.write((b + '\u0000').getBytes("UTF-8")); // Or "Windows-1252" / "ISO-8859-1"
out.flush();
I have added a '\0' as that is used in C/C++ to terminate strings (binary output).
Or maybe "\r\n" might be expected (text output).
The encoding is given explicitly.

Basic PUT, GET request from http server

I'm recently learning how to create sockets to connect to a webserver. I've managed to write a little something in Java:
BufferedReader inUser = new BufferedReader(new
InputStreamReader(System.in));
Socket clientSocket = new Socket("www.google.com", 80); // url expected
DataOutputStream outServer = new DataOutputStream
(clientSocket.getOutputStream());
BufferedReader inServer = new BufferedReader(new
InputStreamReader(clientSocket.getInputStream()));
String sentence = inUser.readLine();
outServer.writeBytes(sentence + '\n');
String modifiedSentence = inServer.readLine();
System.out.println("FROM SERVER: " + modifiedSentence);
inUser.close();
outServer.close();
inServer.close();
clientSocket.close();
I'm also using a socketTest program (from http://sockettest.sourceforge.net/) to test my client. The connection seems fine and I can use the sockettest to receive and send back messages (by hosting a local server). When I try to send a string to a webserver (in my java code it's named 'sentence'), it returns bad requests for random input like 'sd' or 'a', as expected. However, when I type the query I wished to receive feedback on, I don't receive anything. To be sure, this is what I put in (stored in 'sentence'):
GET index.html http/1.0
Either I should get the file if it exists or an exception if something went wrong, right? I don't receive anything though. Stranger yet, I've noticed that the first time I give input, I just have to make sure I have 3 separate random strings (separated by space) to have it accepted as valid input. And any random input I enter afterwards, like 'sd' will also be accepted.
Another observation I made is that the program keeps running. Normally I should read a single line then the program stops. This means it wasn't able to read anything.
I'm using port 80 for all the pages I've tried. Here's a small list of websites I've tried to perform a query on:
- www.google.com
- en.wikipedia.org
- www.cracked.com
I've tried a few others setup for the sole purpose of tutorials. Why don't I receive anything? When I tried it with telnet some seemed to work (though www.google.com always returned a xxx error found).
Try writing an additional "\r\n" before flushing the output stream:
BufferedReader inUser = new BufferedReader(new InputStreamReader(System.in));
URL url = new URL("http://www.google.com");
Socket clientSocket = new Socket(url.getHost(), 80); // url expected
OutputStream output = clientSocket.getOutputStream();
PrintWriter pw = new PrintWriter(output,false);
pw.print("GET index.html HTTP/1.0\r\n");
pw.print("\r\n");
pw.flush();
BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String modifiedSentence = input.readLine();
System.out.println("FROM SERVER: " + modifiedSentence);

Sending Java GET parameters to the server (witout hanging)

I would like to send a GET parameter to a server. I really do not need the InputStream (below), but the request is actually sent when I call "getInputStream". The problem is, this code hangs on getInputStream. The timeout does not apply because the connection is actually established (does not time-out).
What do I need to change so that I'm sending a clean GET to the server without hanging?
URL url = new URL("http://localhost:8888/abc?message=abc"); //[edit]
URLConnection uc = url.openConnection();
uc.setRequestProperty("Accept-Charset", "UTF-8");
uc.setConnectTimeout(1000);
InputStream in = uc.getInputStream();
in.close();
In case it matters, I'm testing with netcat -l as the server instead of using an actual web server. None the less, I would like this code to be very fail-safe so it the server can't adversely effect this code.
I basically gave up in using the URLConnection and wrote the code to use a socket instead. I'm still open for improvements, light-weight posting to a web server is very useful.
URL u = new URL("http://localhost:8888/abc?message=abc");
String get = "";
if (u.getPath() != null)
get += u.getPath();
if (u.getQuery() != null)
get += "?" + u.getQuery();
if (u.getRef() != null)
get += "#" + u.getRef();
Socket socket = new Socket();
socket
.connect(new InetSocketAddress(u.getHost(), u.getPort()),
750);
OutputStream out = socket.getOutputStream();
out.write(("GET " + get + "\n\n").getBytes());
out.close();

Server does not respond to concurrent requests in HTTP/1.1 Client using Java

I'am trying to implement a simple HTTP/1.1 client application against a remote HTTP server. If I have a 301 Moved Permanently response from server, I will try to download the file from it's new location given in server's response. I am able to send first GET message to server and retrieve the new URL where the file I asked was moved.
The problem is that when I send second GET request from my client with new location of the file, server returns null. Not sure if anything goes wrong with writing the client message or reading the server response. Here is my code, any help is appreciated.
else if(serverMessage.equals("HTTP/1.1 301 Moved Permanently"))
{
System.out.println(" A new permanent URL is assigned to the file " + fileName);
serverMessage="";
lineCount=0;
while((serverMessage = reader.readLine()) != null)
{
lineCount++;
System.out.println("reply: " + serverMessage);
if(serverMessage.indexOf("Location") >= 0 )
{
for(int x=serverMessage.indexOf("Location")+10; x<serverMessage.length(); x++)
{
newURL= newURL + serverMessage.charAt(x);
}
}
}
System.out.println("newURL : " + newURL);
host = findHost(newURL);
path = findPath(newURL);
fileName=findFileName(newURL);
clientMessage = "GET ";
clientMessage = clientMessage + path;
clientMessage = clientMessage + " HTTP/1.1\r\nHost: ";
clientMessage = clientMessage + host;
clientMessage = clientMessage + "\r\n\r\n";
System.out.println("client message: \"" + clientMessage +"\"");
writer.newLine();
writer.write(clientMessage);
writer.flush();
serverMessage = reader.readLine();
System.out.println("reply2: " + serverMessage); //returns null!!!
while((serverMessage=reader.readLine())!=null)
{
System.out.println("reply2: " + serverMessage);
}
}
EDIT: Variables of client message are the followings (they all work correctly, tested for existing file - successfully downloaded!)
newURL : http://wlab.cs.bilkent.edu.tr/~cs421/pa1/302-redirect-success.txt
host2: wlab.cs.bilkent.edu.tr
path2: /~cs421/pa1/302-redirect-success.txt
fileName2: 302-redirect-success.txt
Are you using a persistent URLConnection / HttpURLConnection?
You may be receiving null if the connection has been closed by the server.
If you are using persistent connections, the server might have not had the time to respond.
This might describe the problem a little better. Check out the timeout given in doHttpUrlConnectionAction(String desiredUrl). You might find the answer there.
If this is your problem, you can try to do multiple reads at 0.1 second intervals for say ... 1-5 seconds. This is to make sure you get the response fast and don't have to wait the full timeout to make sure that the server has responded.

Categories

Resources