UPnP fixes part 6:

Fix malformed HTTP requests
Check HTTP response code in Parser
Check content type in Parser
Debug log in Parser
Show device URL in CLI
Don't retry after parser exception
Close resources in finally block
This commit is contained in:
zzz
2020-05-22 18:22:56 +00:00
parent a3fc8af1dd
commit 6aa81f7ec6
3 changed files with 53 additions and 13 deletions

View File

@ -1634,6 +1634,9 @@ public class UPnP extends ControlPoint implements DeviceChangeListener, EventLis
": " + DataHelper.escapeHTML(device.getFriendlyName()) + "</h3>");
System.out.println("<p>UDN: " + DataHelper.escapeHTML(device.getUDN()));
System.out.println("<br>IP: " + getIP(device));
String loc = device.getLocation();
if (loc != null && loc.length() > 0)
System.out.println("<br>URL: <a href=\"" + loc + "\">" + loc + "</a>");
System.out.println(sb.toString());
sb.setLength(0);
}

View File

@ -64,6 +64,7 @@ package org.cybergarage.upnp;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;
import org.cybergarage.http.HTTPRequest;
import org.cybergarage.http.HTTPRequestListener;
@ -253,6 +254,15 @@ public class ControlPoint implements HTTPRequestListener
String location = ssdpPacket.getLocation();
try {
URL locationUrl = new URL(location);
// I2P
// Roku fake json port, the real UPnP port is 8060
if (locationUrl.getPort() == 9080) {
String lcusn = usn.toLowerCase(Locale.US);
if (lcusn.contains("rku") || lcusn.contains("roku")) {
Debug.warning("Ignoring Roku at " + location);
return;
}
}
Parser parser = UPnP.getXMLParser();
Node rootNode = parser.parse(locationUrl);
Device rootDev = getDevice(rootNode);
@ -270,12 +280,10 @@ public class ControlPoint implements HTTPRequestListener
performAddDeviceListener( rootDev );
}
catch (MalformedURLException me) {
Debug.warning(ssdpPacket.toString());
Debug.warning(me);
Debug.warning("Bad location: " + location, me);
}
catch (ParserException pe) {
Debug.warning(ssdpPacket.toString());
Debug.warning(pe);
Debug.warning("Error parsing data at location: " + location, pe);
}
}

View File

@ -21,6 +21,7 @@ package org.cybergarage.xml;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.net.HttpURLConnection;
@ -29,6 +30,7 @@ import java.net.URL;
import org.cybergarage.http.HTTP;
import org.cybergarage.http.HTTPRequest;
import org.cybergarage.http.HTTPResponse;
import org.cybergarage.util.Debug;
public abstract class Parser
{
@ -58,9 +60,15 @@ public abstract class Parser
if (port == -1)
port = 80;
String uri = locationURL.getPath();
// I2P note: Roku port 9080 now ignored in ControlPoint.addDevice()
// I2P fix - Roku
if (uri.length() <= 0)
uri = "/";
HttpURLConnection urlCon = null;
InputStream urlIn = null;
try {
HttpURLConnection urlCon = (HttpURLConnection)locationURL.openConnection();
urlCon = (HttpURLConnection)locationURL.openConnection();
// I2P mods to prevent hangs (see HTTPRequest for more info)
// this seems to work, getInputStream actually does the connect(),
// (as shown by a thread dump)
@ -73,29 +81,50 @@ public abstract class Parser
if (host != null)
urlCon.setRequestProperty(HTTP.HOST, host);
InputStream urlIn = urlCon.getInputStream();
// I2P fix
int code = urlCon.getResponseCode();
if (code < 200 || code >= 300)
throw new ParserException("Bad response code " + code);
// I2P fix - Roku port 9080
// not valid json either; returns "status=ok"
if ("application/json".equals(urlCon.getContentType()))
throw new ParserException("JSON response");
urlIn = urlCon.getInputStream();
Node rootElem = parse(urlIn);
urlIn.close();
urlCon.disconnect();
return rootElem;
} catch (ParserException pe) {
throw pe;
} catch (Exception e) {
// Why try twice???
//throw new ParserException(e);
Debug.warning("Failed fetch but retrying with HTTPRequest, URL: " + locationURL, e);
} finally {
if (urlIn != null) try { urlIn.close(); } catch (IOException ioe) {}
if (urlCon != null) urlCon.disconnect();
}
HTTPRequest httpReq = new HTTPRequest();
httpReq.setMethod(HTTP.GET);
httpReq.setURI(uri);
HTTPResponse httpRes = httpReq.post(host, port);
if (httpRes.isSuccessful() == false)
throw new ParserException("HTTP comunication failed: no answer from peer." +
"Unable to retrive resoure -> "+locationURL.toString());
if (!httpRes.isSuccessful())
throw new ParserException("HTTP comunication failed. " +
"Unable to retrieve resource -> " + locationURL +
"\nRequest:\n" + httpReq +
"\nResponse:\n" + httpRes);
String content = new String(httpRes.getContent());
ByteArrayInputStream strBuf = new ByteArrayInputStream(content.getBytes());
return parse(strBuf);
try {
return parse(strBuf);
} catch (ParserException pe) {
Debug.warning("Parse error at resource " + locationURL +
"\nRequest:\n" + httpReq +
"\nResponse:\n" + httpRes, pe);
throw pe;
}
}
////////////////////////////////////////////////