| 
					
				 | 
			
			
				@@ -3,6 +3,7 @@ using System.Collections.Generic; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.IO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Linq; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Text; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Threading.Tasks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Xml; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using Emby.Dlna.Didl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Controller.Configuration; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -15,44 +16,34 @@ namespace Emby.Dlna.Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        protected readonly IServerConfigurationManager Config; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        protected readonly ILogger _logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        protected IServerConfigurationManager Config { get; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        protected ILogger Logger { get; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         protected BaseControlHandler(IServerConfigurationManager config, ILogger logger) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             Config = config; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _logger = logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger = logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public ControlResponse ProcessControlRequest(ControlRequest request) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public async Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLog; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (enableDebugLogging) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    LogRequest(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var response = ProcessControlRequestInternal(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (enableDebugLogging) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    LogResponse(response); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                LogRequest(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var response = await ProcessControlRequestInternalAsync(request).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                LogResponse(response); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return response; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             catch (Exception ex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _logger.LogError(ex, "Error processing control request"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Logger.LogError(ex, "Error processing control request"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return new ControlErrorHandler().GetResponse(ex); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return ControlErrorHandler.GetResponse(ex); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private ControlResponse ProcessControlRequestInternal(ControlRequest request) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private async Task<ControlResponse> ProcessControlRequestInternalAsync(ControlRequest request) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ControlRequestInfo requestInfo = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -63,16 +54,17 @@ namespace Emby.Dlna.Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     ValidationType = ValidationType.None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     CheckCharacters = false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     IgnoreProcessingInstructions = true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    IgnoreComments = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    IgnoreComments = true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Async = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 using (var reader = XmlReader.Create(streamReader, readerSettings)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    requestInfo = ParseRequest(reader); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    requestInfo = await ParseRequestAsync(reader).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _logger.LogDebug("Received control request {0}", requestInfo.LocalName); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger.LogDebug("Received control request {0}", requestInfo.LocalName); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var result = GetResult(requestInfo.LocalName, requestInfo.Headers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -114,17 +106,15 @@ namespace Emby.Dlna.Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 IsSuccessful = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //logger.LogDebug(xml); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             controlResponse.Headers.Add("EXT", string.Empty); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return controlResponse; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private ControlRequestInfo ParseRequest(XmlReader reader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private async Task<ControlRequestInfo> ParseRequestAsync(XmlReader reader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            reader.MoveToContent(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            await reader.MoveToContentAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            await reader.ReadAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Loop through each element 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             while (!reader.EOF && reader.ReadState == ReadState.Interactive) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -139,37 +129,38 @@ namespace Emby.Dlna.Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                     using (var subReader = reader.ReadSubtree()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        return ParseBodyTag(subReader); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                        return await ParseBodyTagAsync(subReader).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    await reader.ReadAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                reader.Skip(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                await reader.SkipAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    await reader.ReadAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return new ControlRequestInfo(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private ControlRequestInfo ParseBodyTag(XmlReader reader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private async Task<ControlRequestInfo> ParseBodyTagAsync(XmlReader reader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var result = new ControlRequestInfo(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            reader.MoveToContent(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            await reader.MoveToContentAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            await reader.ReadAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Loop through each element 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             while (!reader.EOF && reader.ReadState == ReadState.Interactive) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -183,28 +174,28 @@ namespace Emby.Dlna.Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         using (var subReader = reader.ReadSubtree()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            ParseFirstBodyChild(subReader, result.Headers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        await reader.ReadAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    await reader.ReadAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void ParseFirstBodyChild(XmlReader reader, IDictionary<string, string> headers) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary<string, string> headers) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            reader.MoveToContent(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            await reader.MoveToContentAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            await reader.ReadAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Loop through each element 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             while (!reader.EOF && reader.ReadState == ReadState.Interactive) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -212,20 +203,20 @@ namespace Emby.Dlna.Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if (reader.NodeType == XmlNodeType.Element) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     // TODO: Should we be doing this here, or should it be handled earlier when decoding the request? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    headers[reader.LocalName.RemoveDiacritics()] = reader.ReadElementContentAsString(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    headers[reader.LocalName.RemoveDiacritics()] = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    reader.Read(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    await reader.ReadAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private class ControlRequestInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public string LocalName; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public string NamespaceURI; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            public IDictionary<string, string> Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            public string LocalName { get; set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            public string NamespaceURI { get; set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -237,10 +228,7 @@ namespace Emby.Dlna.Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var originalHeaders = request.Headers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _logger.LogDebug("Control request. Headers: {0}", headers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger.LogDebug("Control request. Headers: {@Headers}", request.Headers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private void LogResponse(ControlResponse response) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -250,11 +238,7 @@ namespace Emby.Dlna.Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var originalHeaders = response.Headers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            //builder.Append(response.Xml); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _logger.LogDebug("Control response. Headers: {0}", headers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger.LogDebug("Control response. Headers: {@Headers}\n{Xml}", response.Headers, response.Xml); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |