Yortw / RSSDP

Really Simple Service Discovery Protocol - a 100% .Net implementation of the SSDP protocol for publishing custom/basic devices, and discovering all device types on a network.
http://yortw.github.io/RSSDP/
MIT License
282 stars 66 forks source link

404 on HTTP Request - unhandled exception #90

Closed winkmichael closed 5 years ago

winkmichael commented 5 years ago

Hey there, cool project. I am using the example code and get the following error when I run into a device with a 404. I guess I could handle this exception slightly using an UnhandledException overload, but I was thinking there might be a fix in the lib for this?

Unhandled Exception: System.UriFormatException: Invalid URI: The hostname could not be parsed. at System.Uri.CreateThis (System.String uri, System.Boolean dontEscape, System.UriKind uriKind) [0x0007d] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/System/net/System/UriExt.cs:56 at System.Uri..ctor (System.String uriString, System.UriKind uriKind) [0x00014] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/System/net/System/URI.cs:450 at Rssdp.SsdpDevice.StringToUri (System.String value) [0x00008] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.SsdpDevice.SetPropertyFromReader (System.Xml.XmlReader reader, Rssdp.SsdpDevice device) [0x00264] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.SsdpDevice.LoadDeviceProperties (System.Xml.XmlReader reader, Rssdp.SsdpDevice device) [0x0002c] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.SsdpDevice..ctor (System.String deviceDescriptionXml) [0x00044] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.SsdpRootDevice..ctor (System.Uri location, System.TimeSpan cacheLifetime, System.String deviceDescriptionXml) [0x00000] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.DiscoveredSsdpDevice.GetDeviceInfo (System.Net.Http.HttpClient downloadHttpClient) [0x0011a] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.DiscoveredSsdpDevice.GetDeviceInfo () [0x00083] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at wDisco.MainClass+Search.deviceLocator_DeviceAvailable (System.Object sender, Rssdp.DeviceAvailableEventArgs e) [0x00062] in /Users/michaelm/xmichael99@gmail.com/Projects/wDisco/wDisco/Program.cs:117 at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b__6_1 (System.Object state) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1039 at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) [0x0000d] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1308 at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:961 at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:908 at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () [0x00021] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1285 at System.Threading.ThreadPoolWorkQueue.Dispatch () [0x00074] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:858 at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1213

Unhandled Exception: System.Net.Http.HttpRequestException: 404 (Not Found) at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode () [0x0000a] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/System.Net.Http/System.Net.Http/HttpResponseMessage.cs:122 at Rssdp.DiscoveredSsdpDevice.GetDeviceInfo (System.Net.Http.HttpClient downloadHttpClient) [0x00094] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.DiscoveredSsdpDevice.GetDeviceInfo () [0x00083] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at wDisco.MainClass+Search.deviceLocator_DeviceAvailable (System.Object sender, Rssdp.DeviceAvailableEventArgs e) [0x00062] in /Users/michaelm/xmichael99@gmail.com/Projects/wDisco/wDisco/Program.cs:117 at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b__6_1 (System.Object state) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1039 at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) [0x0000d] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1308 at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:961 at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:908 at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () [0x00021] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1285 at System.Threading.ThreadPoolWorkQueue.Dispatch () [0x00074] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:858 at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1213 FreeBSD router

[ERROR] FATAL UNHANDLED EXCEPTION: System.UriFormatException: Invalid URI: The hostname could not be parsed. at System.Uri.CreateThis (System.String uri, System.Boolean dontEscape, System.UriKind uriKind) [0x0007d] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/System/net/System/UriExt.cs:56 at System.Uri..ctor (System.String uriString, System.UriKind uriKind) [0x00014] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/System/net/System/URI.cs:450 at Rssdp.SsdpDevice.StringToUri (System.String value) [0x00008] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.SsdpDevice.SetPropertyFromReader (System.Xml.XmlReader reader, Rssdp.SsdpDevice device) [0x00264] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.SsdpDevice.LoadDeviceProperties (System.Xml.XmlReader reader, Rssdp.SsdpDevice device) [0x0002c] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.SsdpDevice..ctor (System.String deviceDescriptionXml) [0x00044] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.SsdpRootDevice..ctor (System.Uri location, System.TimeSpan cacheLifetime, System.String deviceDescriptionXml) [0x00000] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.DiscoveredSsdpDevice.GetDeviceInfo (System.Net.Http.HttpClient downloadHttpClient) [0x0011a] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.DiscoveredSsdpDevice.GetDeviceInfo () [0x00083] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at wDisco.MainClass+Search.deviceLocator_DeviceAvailable (System.Object sender, Rssdp.DeviceAvailableEventArgs e) [0x00062] in /Users/michaelm/xmichael99@gmail.com/Projects/wDisco/wDisco/Program.cs:117 at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b6_1 (System.Object state) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1039 at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) [0x0000d] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1308 at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:961 at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:908 at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () [0x00021] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1285 at System.Threading.ThreadPoolWorkQueue.Dispatch () [0x00074] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:858 at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1213 [ERROR] FATAL UNHANDLED EXCEPTION: System.Net.Http.HttpRequestException: 404 (Not Found) at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode () [0x0000a] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/System.Net.Http/System.Net.Http/HttpResponseMessage.cs:122 at Rssdp.DiscoveredSsdpDevice.GetDeviceInfo (System.Net.Http.HttpClient downloadHttpClient) [0x00094] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at Rssdp.DiscoveredSsdpDevice.GetDeviceInfo () [0x00083] in <5569f5ca71f84fafb50ec4dfa2ebd196>:0 at wDisco.MainClass+Search.deviceLocator_DeviceAvailable (System.Object sender, Rssdp.DeviceAvailableEventArgs e) [0x00062] in /Users/michaelm/xmichael99@gmail.com/Projects/wDisco/wDisco/Program.cs:117 at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b6_1 (System.Object state) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1039 at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) [0x0000d] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1308 at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:961 at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:908 at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () [0x00021] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1285 at System.Threading.ThreadPoolWorkQueue.Dispatch () [0x00074] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:858 at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-06/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1213

Here is what I am running

public static void Main(string[] args) { Search searcher = new Search(); searcher.BeginSearch(); Thread.Sleep(10000); } public class Search { private SsdpDeviceLocator _DeviceLocator;

        public void BeginSearch()
        {
            _DeviceLocator = new SsdpDeviceLocator();

            // (Optional) Set the filter so we only see notifications for devices we care about 
            // (can be any search target value i.e device type, uuid value etc - any value that appears in the 
            // DiscoverdSsdpDevice.NotificationType property or that is used with the searchTarget parameter of the Search method).
            _DeviceLocator.NotificationFilter = "upnp:rootdevice";

            // Connect our event handler so we process devices as they are found
            _DeviceLocator.DeviceAvailable += deviceLocator_DeviceAvailable;

            // Enable listening for notifications (optional)
            _DeviceLocator.StartListeningForNotifications();

            // Perform a search so we don't have to wait for devices to broadcast notifications 
            // again to get any results right away (notifications are broadcast periodically).
            _DeviceLocator.SearchAsync();

            Console.ReadLine();
        }

        // Process each found device in the event handler
        async static void deviceLocator_DeviceAvailable(object sender, DeviceAvailableEventArgs e)
        {
            //Device data returned only contains basic device details and location of full device description.
            Console.WriteLine("Found " + e.DiscoveredDevice.Usn + " at " + e.DiscoveredDevice.DescriptionLocation.ToString());

            //Can retrieve the full device description easily though.
            var fullDevice = await e.DiscoveredDevice.GetDeviceInfo();
            Console.WriteLine(fullDevice.FriendlyName);
            Console.WriteLine();
        }
    }

Thank you very much for taking the time to review this issue and making this project!

Yortw commented 5 years ago

Hi,

Thanks for getting in touch, I'm glad you're finding RSSDP useful.

If I am reading the exception details correctly, this error is happening in the deviceLocator_DeviceAvailable event handler in the sample code/your app when the await e.DiscoveredDevice.GetDeviceInfo() block is executed.

This involved doing a network call to the server, and anything that could normally go wrong with a network call can happen at this point. That includes the network being down, a timeout, DNS failure, a 404/401/429/500 or other HTTP error etc. The library cannot and should not handle this, if it can't get the data from the device then it cannot return the device information that is expected as the result of GetDeviceInfo. It could I guess catch any error and return null, but that would be bad as the calling application cannot then determine why it got null - was it a timeout or 429 where a retry might be appropriate? Is the network down, should it wait for a reconnect? etc. As such, there isn't a 'fix' available and I'm not sure what one would look like in terms of changing the library.

I wouldn't use an 'unhandled exception' event for a variety of reasons. I personally think the correct thing to do would be to add a try/catch block around that line of code (the call to GetDeviceInfo) in the application, and handle the error(s) appropriately in the catch. What that means depends on the app. Perhaps you just ignore devices that can't be contacted. Perhaps you add them to a separate list of problem devices which is displayed to the user at some point. Perhaps for some exceptions you decide to ignore the device, and for other exceptions you retry on up to some number of retries.

I hope that helps, if not or if I've misunderstood, please let me know. Thanks again.

winkmichael commented 5 years ago

Thank for your very thoughtful and detailed response. Upon reading your response I sure do feel like a dummy, I honestly didn't even bother to read into the sample code instead I went looking through your code trying to see how the HTTP connection was made, thinking that there was a missing try catch for a 404 exception type, and that it should be handled up stream.

A simply try catch exception type seems to get it. I can't seem to catch a WebException, but that is probably ok (;

Thanks again for your time and help.

Yortw commented 5 years ago

Hi,

No need to feel silly, it's a complicated stacktrace and being unfamiliar with the code doesn't help, I can easily see how it would be confusing :)

Good luck with your project!