public IResponse HandleRequest(IRequest request) { if (Authorizer != null && !IPAddress.IsLoopback(request.RemoteEndpoint.Address) && !Authorizer.Authorize( request.Headers, request.RemoteEndpoint )) { throw new HttpStatusException(HttpCode.Denied); } var path = request.Path.Substring(Prefix.Length); if (path == "description.xml") { return(new StringResponse( HttpCode.Ok, "text/xml", GenerateDescriptor(request.LocalEndPoint.Address) )); } if (path == "contentDirectory.xml") { return(new ResourceResponse( HttpCode.Ok, "text/xml", "contentDirectory.xml" )); } if (path == "connectionManager.xml") { return(new ResourceResponse( HttpCode.Ok, "text/xml", "connectionManager.xml" )); } if (path == "MSMediaReceiverRegistrar.xml") { return(new ResourceResponse( HttpCode.Ok, "text/xml", "MSMediaReceiverRegistrar.xml" )); } if (path == "control") { return(ProcessSoapRequest(request)); } if (path.StartsWith("file/", StringComparison.Ordinal)) { var id = path.Split('/')[1]; Logger.LogTrace($"Serving file {id}"); var item = GetItem(id, true) as IMediaResource; return(new ItemResponse(Prefix, request, item)); } if (path.StartsWith("cover/", StringComparison.Ordinal)) { var id = path.Split('/')[1]; Logger.LogTrace($"Serving cover {id}"); var item = GetItem(id, false) as IMediaCover; if (item == null) { throw new HttpStatusException(HttpCode.NotFound); } return(new ItemResponse(Prefix, request, item.Cover, "Interactive")); } if (path.StartsWith("subtitle/", StringComparison.Ordinal)) { var id = path.Split('/')[1]; Logger.LogTrace($"Serving subtitle {id}"); var item = GetItem(id, false) as IMetaVideoItem; if (item == null) { throw new HttpStatusException(HttpCode.NotFound); } return(new ItemResponse(Prefix, request, item.Subtitle, "Background")); } if (string.IsNullOrEmpty(path) || path == "index.html") { return(new Redirect(request, Prefix + "index/0")); } if (path.StartsWith("index/", StringComparison.Ordinal)) { var id = path.Substring("index/".Length); var item = GetItem(id, false); return(ProcessHtmlRequest(item)); } if (request.Method == "SUBSCRIBE") { var res = new StringResponse(HttpCode.Ok, string.Empty); res.Headers.Add("SID", $"uuid:{Guid.NewGuid()}"); res.Headers.Add("TIMEOUT", request.Headers["timeout"]); return(res); } if (request.Method == "UNSUBSCRIBE") { return(new StringResponse(HttpCode.Ok, string.Empty)); } Logger.LogTrace($"Did not understand {request.Method} {path}"); throw new HttpStatusException(HttpCode.NotFound); }
private IResponse ProcessSoapRequest(IRequest request) { var soap = new XmlDocument(); try //POST /mm-1/control HTTP/1.1 { soap.LoadXml(request.Body); } catch (Exception ex) { Logger.LogError(ex, $"ProcessSoapRequest. Error Loading Request From [{ request.RemoteEndpoint.Address }], Body [{ request.Body }]"); } var sparams = new RawHeaders(); var body = soap.SelectSingleNode("//soap:Body", namespaceMgr); if (body == null) { throw new HttpStatusException(HttpCode.InternalError); } var method = body.FirstChild; foreach (var p in method.ChildNodes) { var e = p as XmlElement; if (e == null) { continue; } sparams.Add(e.LocalName, e.InnerText.Trim()); } var env = new XmlDocument(); env.AppendChild(env.CreateXmlDeclaration("1.0", "utf-8", "yes")); var envelope = env.CreateElement("SOAP-ENV", "Envelope", NS_SOAPENV); env.AppendChild(envelope); envelope.SetAttribute( "encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/"); var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV); env.DocumentElement?.AppendChild(rbody); var code = HttpCode.Ok; try { IEnumerable <KeyValuePair <string, string> > result; switch (method.LocalName) { case "GetSearchCapabilities": result = HandleGetSearchCapabilities(); break; case "GetSortCapabilities": result = HandleGetSortCapabilities(); break; case "GetSystemUpdateID": result = HandleGetSystemUpdateID(); break; case "Browse": result = HandleBrowse(request, sparams); break; case "X_GetFeatureList": result = HandleXGetFeatureList(); break; case "X_SetBookmark": result = HandleXSetBookmark(sparams); break; case "GetCurrentConnectionIDs": result = HandleGetCurrentConnectionIDs(); break; case "GetCurrentConnectionInfo": result = HandleGetCurrentConnectionInfo(); break; case "GetProtocolInfo": result = HandleGetProtocolInfo(); break; case "IsAuthorized": result = HandleIsAuthorized(); break; case "IsValidated": result = HandleIsValidated(); break; case "RegisterDevice": result = HandleRegisterDevice(); break; default: throw new HttpStatusException(HttpCode.NotFound); } var response = env.CreateElement($"u:{method.LocalName}Response", method.NamespaceURI); rbody.AppendChild(response); foreach (var i in result) { var ri = env.CreateElement(i.Key); ri.InnerText = i.Value; response.AppendChild(ri); } } catch (Exception ex) { code = HttpCode.InternalError; var fault = env.CreateElement("SOAP-ENV", "Fault", NS_SOAPENV); var faultCode = env.CreateElement("faultcode"); faultCode.InnerText = "500"; fault.AppendChild(faultCode); var faultString = env.CreateElement("faultstring"); faultString.InnerText = ex.ToString(); fault.AppendChild(faultString); var detail = env.CreateDocumentFragment(); detail.InnerXml = "<detail><UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\"><errorCode>401</errorCode><errorDescription>Invalid Action</errorDescription></UPnPError></detail>"; fault.AppendChild(detail); rbody.AppendChild(fault); Trace.WriteLine($"Invalid call: Action: {method.LocalName}, Params: {sparams}, Problem {ex.Message}"); } var rv = new StringResponse(code, "text/xml", env.OuterXml); rv.Headers.Add("EXT", string.Empty); return(rv); }