protected override object DoDeserializeValue(XmlReader reader, bool isSimpleValue) { if (SoapHelper.ReadEmptyStartElement(reader)) // Read start of enclosing element { return(null); } if (!reader.MoveToAttribute("type")) { throw new ArgumentException("Cannot deserialize value, 'type' attribute missing"); } String typeStr = reader.ReadContentAsString(); Type type = Type.GetType(typeStr); reader.MoveToElement(); HomogenousMap result = new HomogenousMap(type, typeof(int)); if (SoapHelper.ReadEmptyStartElement(reader, "Values")) { return(result); } while (reader.NodeType != XmlNodeType.EndElement) { result.Add(MediaItemAspect.DeserializeValue(reader, type), MediaItemAspect.DeserializeValue(reader, typeof(int))); } reader.ReadEndElement(); // End of enclosing element return(result); }
protected static IList <object> ParseResult(TextReader textReader, CpAction action, bool sourceSupportsUPnP11) { IList <object> outParameterValues = new List <object>(); using (XmlReader reader = XmlReader.Create(textReader, UPnPConfiguration.DEFAULT_XML_READER_SETTINGS)) { reader.MoveToContent(); // Parse SOAP envelope reader.ReadStartElement("Envelope", UPnPConsts.NS_SOAP_ENVELOPE); reader.ReadStartElement("Body", UPnPConsts.NS_SOAP_ENVELOPE); // Reader is positioned at the action element string serviceTypeVersion_URN = reader.NamespaceURI; string type; int version; // Parse service and action if (!ParserHelper.TryParseTypeVersion_URN(serviceTypeVersion_URN, out type, out version)) { throw new ArgumentException("Invalid service type or version"); } string actionName = reader.LocalName; if (!actionName.EndsWith("Response") || actionName.Substring(0, actionName.Length - "Response".Length) != action.Name) { throw new ArgumentException("Invalid action name in result message"); } IEnumerator <CpArgument> formalArgumentEnumer = action.OutArguments.GetEnumerator(); if (!SoapHelper.ReadEmptyStartElement(reader)) { // Parse and check output parameters while (reader.NodeType != XmlNodeType.EndElement) { string argumentName = reader.Name; // Arguments don't have a namespace, so take full name if (!formalArgumentEnumer.MoveNext()) // Too many arguments { throw new ArgumentException("Invalid out argument count"); } if (formalArgumentEnumer.Current.Name != argumentName) { throw new ArgumentException("Invalid argument name"); } object value; if (SoapHelper.ReadNull(reader)) { value = null; } else { formalArgumentEnumer.Current.SoapParseArgument(reader, !sourceSupportsUPnP11, out value); } outParameterValues.Add(value); } } if (formalArgumentEnumer.MoveNext()) // Too few arguments { throw new ArgumentException("Invalid out argument count"); } } return(outParameterValues); }
public static MediaItemAspect Deserialize(XmlReader reader) { if (!reader.MoveToAttribute("Id")) { throw new ArgumentException("Media item aspect cannot be deserialized: 'Id' attribute missing"); } Guid aspectTypeId = new Guid(reader.ReadContentAsString()); reader.MoveToElement(); IMediaItemAspectTypeRegistration miatr = ServiceRegistration.Get <IMediaItemAspectTypeRegistration>(); MediaItemAspectMetadata miaType; if (!miatr.LocallyKnownMediaItemAspectTypes.TryGetValue(aspectTypeId, out miaType)) { throw new ArgumentException(string.Format("Media item aspect cannot be deserialized: Unknown media item aspect type '{0}'", aspectTypeId)); } MediaItemAspect result = new MediaItemAspect(miaType); if (SoapHelper.ReadEmptyStartElement(reader, "Aspect")) { return(result); } while (reader.NodeType != XmlNodeType.EndElement) { if (!reader.MoveToAttribute("Name")) { throw new ArgumentException("Media item aspect attribute cannot be deserialized: 'Name' attribute missing"); } String attributeName = reader.ReadContentAsString(); reader.MoveToElement(); if (SoapHelper.ReadEmptyStartElement(reader, "Attr")) { continue; } MediaItemAspectMetadata.AttributeSpecification attributeSpec; if (!miaType.AttributeSpecifications.TryGetValue(attributeName, out attributeSpec)) { throw new ArgumentException(string.Format( "Media item aspect attribute cannot be deserialized: Unknown attribute specification '{0}'", attributeName)); } if (attributeSpec.IsCollectionAttribute) { IList valuesCollection = attributeSpec.CreateValuesCollection(); while (reader.NodeType != XmlNodeType.EndElement) { valuesCollection.Add(DeserializeValue(reader, attributeSpec.AttributeType)); } result.SetCollectionAttribute(attributeSpec, valuesCollection); } else { result.SetAttribute(attributeSpec, DeserializeValue(reader, attributeSpec.AttributeType)); } reader.ReadEndElement(); // Attr } reader.ReadEndElement(); // Aspect return(result); }
protected override object DoDeserializeValue(XmlReader reader, bool isSimpleValue) { ICollection <ResourcePathMetadata> result = new List <ResourcePathMetadata>(); if (SoapHelper.ReadEmptyStartElement(reader)) // Read start of enclosing element { return(result); } while (reader.NodeType != XmlNodeType.EndElement) { result.Add(ResourcePathMetadata.Deserialize(reader)); } reader.ReadEndElement(); // End of enclosing element return(result); }
protected override object DoDeserializeValue(XmlReader reader, bool isSimpleValue) { if (SoapHelper.ReadEmptyStartElement(reader)) // Read start of enclosing element { return(null); } Schedule result = null; while (reader.NodeType != XmlNodeType.EndElement) { result = Schedule.Deserialize(reader); } reader.ReadEndElement(); // End of enclosing element return(result); }
protected override object DoDeserializeValue(XmlReader reader, bool isSimpleValue) { IDictionary <string, MediaCategory_DTO> result_dtos = new Dictionary <string, MediaCategory_DTO>(); if (SoapHelper.ReadEmptyStartElement(reader)) // Read start of enclosing element { return(new List <MediaCategory>()); } while (reader.NodeType != XmlNodeType.EndElement) { MediaCategory_DTO result_dto = MediaCategory_DTO.Deserialize(reader); result_dtos.Add(result_dto.CategoryName, result_dto); } reader.ReadEndElement(); // End of enclosing element return(new List <MediaCategory>(result_dtos.Select(mCatDtoKvp => mCatDtoKvp.Value.GetMediaCategory(result_dtos)))); }
protected static IList <object> ParseResult(TextReader textReader, CpAction action, bool sourceSupportsUPnP11) { object[] outParameterValues = new object[action.OutArguments.Count]; using (XmlReader reader = XmlReader.Create(textReader, UPnPConfiguration.DEFAULT_XML_READER_SETTINGS)) { reader.MoveToContent(); // Parse SOAP envelope reader.ReadStartElement("Envelope", UPnPConsts.NS_SOAP_ENVELOPE); reader.ReadStartElement("Body", UPnPConsts.NS_SOAP_ENVELOPE); // Reader is positioned at the action element string serviceTypeVersion_URN = reader.NamespaceURI; string type; int version; // Parse service and action if (!ParserHelper.TryParseTypeVersion_URN(serviceTypeVersion_URN, out type, out version)) { throw new ArgumentException("Invalid service type or version"); } string actionName = reader.LocalName; if (!actionName.EndsWith("Response") || actionName.Substring(0, actionName.Length - "Response".Length) != action.Name) { throw new ArgumentException("Invalid action name in result message"); } // UPnP spec says we have to be able to handle return values being out // of order to support UPnP 1.0 devices. See UPnP-arch-DeviceArchitecture-v1.1 // section 2.5.4. We need a dictionary to make this easy. IDictionary <string, int> formalArgIdxDictionary = new Dictionary <string, int>(); for (int i = 0; i < action.OutArguments.Count; i++) { formalArgIdxDictionary.Add(action.OutArguments[i].Name, i); } int outArgCount = 0; if (!SoapHelper.ReadEmptyStartElement(reader)) { // Parse and check output parameters while (reader.NodeType != XmlNodeType.EndElement) { string argumentName = reader.Name; // Arguments don't have a namespace, so take full name int formalArgumentIndex; if (!formalArgIdxDictionary.TryGetValue(argumentName, out formalArgumentIndex)) { throw new ArgumentException("Invalid argument name"); } CpArgument formalArgument = action.OutArguments[formalArgumentIndex]; // Get the argument value and store it in the correct position in the return list. object value = null; if (!SoapHelper.ReadNull(reader)) { formalArgument.SoapParseArgument(reader, !sourceSupportsUPnP11, out value); } outParameterValues[formalArgumentIndex] = value; outArgCount++; // Don't allow duplicates of the same argument. formalArgIdxDictionary.Remove(formalArgument.Name); } } if (outArgCount != action.OutArguments.Count) // Too few arguments { throw new ArgumentException("Invalid out argument count"); } } return(outParameterValues); }
/// <summary> /// Handler method for SOAP control requests. /// </summary> /// <param name="service">The service whose action was called.</param> /// <param name="messageStream">The stream which contains the HTTP message body with the SOAP envelope.</param> /// <param name="streamEncoding">Encoding of the <paramref name="messageStream"/>.</param> /// <param name="subscriberSupportsUPnP11">Should be set if the requester sent a user agent header which denotes a UPnP /// version of 1.1. If set to <c>false</c>, in- and out-parameters with extended data type will be deserialized/serialized /// using the string-equivalent of the values.</param> /// <param name="context">Context object holding data for the current action call.</param> /// <param name="result">SOAP result - may be an action result, a SOAP fault or <c>null</c> if no body should /// be sent in the HTTP response.</param> /// <returns>HTTP status code to be sent. Should be /// <list> /// <item><see cref="HttpStatusCode.OK"/> If the action could be evaluated correctly and produced a SOAP result.</item> /// <item><see cref="HttpStatusCode.InternalServerError"/> If the result is a SOAP fault.</item> /// <item><see cref="HttpStatusCode.BadRequest"/> If the message stream was malformed.</item> /// </list> /// </returns> public static HttpStatusCode HandleRequest(DvService service, Stream messageStream, Encoding streamEncoding, bool subscriberSupportsUPnP11, CallContext context, out string result) { UPnPError res; try { IList <object> inParameterValues = null; // Default to null if there aren't parameters, will be lazily initialized later DvAction action; using (StreamReader streamReader = new StreamReader(messageStream, streamEncoding)) using (XmlReader reader = XmlReader.Create(streamReader, UPnPConfiguration.DEFAULT_XML_READER_SETTINGS)) { reader.MoveToContent(); // Parse SOAP envelope reader.ReadStartElement("Envelope", UPnPConsts.NS_SOAP_ENVELOPE); reader.ReadStartElement("Body", UPnPConsts.NS_SOAP_ENVELOPE); // Reader is positioned at the action element string serviceTypeVersion_URN = reader.NamespaceURI; string type; int version; // Parse service and action if (!ParserHelper.TryParseTypeVersion_URN(serviceTypeVersion_URN, out type, out version)) { throw new MediaPortal.Utilities.Exceptions.InvalidDataException("Unable to parse service type and version URN '{0}'", serviceTypeVersion_URN); } string actionName = reader.LocalName; if (!service.Actions.TryGetValue(actionName, out action)) { result = CreateFaultDocument(401, "Invalid Action"); return(HttpStatusCode.InternalServerError); } IEnumerator <DvArgument> formalArgumentEnumer = action.InArguments.GetEnumerator(); if (!SoapHelper.ReadEmptyStartElement(reader)) // Action name { while (reader.NodeType != XmlNodeType.EndElement) { string argumentName = reader.Name; // Arguments don't have a namespace, so take full name if (!formalArgumentEnumer.MoveNext() || formalArgumentEnumer.Current.Name != argumentName) { // Too many arguments result = CreateFaultDocument(402, "Invalid Args"); return(HttpStatusCode.InternalServerError); } object value; if (SoapHelper.ReadNull(reader)) { value = null; } else { res = formalArgumentEnumer.Current.SoapParseArgument(reader, !subscriberSupportsUPnP11, out value); if (res != null) { result = CreateFaultDocument(res.ErrorCode, res.ErrorDescription); return(HttpStatusCode.InternalServerError); } } if (inParameterValues == null) { inParameterValues = new List <object>(); } inParameterValues.Add(value); } } if (formalArgumentEnumer.MoveNext()) { // Too few arguments result = CreateFaultDocument(402, "Invalid Args"); return(HttpStatusCode.InternalServerError); } } IList <object> outParameterValues; // Invoke action try { res = action.InvokeAction(inParameterValues, out outParameterValues, false, context); // outParameterValues can be null if the action has no output parameters. Setting it to an empty list makes // it easier to check parameter count later. if (outParameterValues == null) { outParameterValues = EMPTY_OBJECT_LIST; } } catch (Exception e) { UPnPConfiguration.LOGGER.Warn("SOAPHandler: Error invoking UPnP action '{0}'", e, action.Name); result = CreateFaultDocument(501, "Action Failed"); return(HttpStatusCode.InternalServerError); } if (res != null) { result = CreateFaultDocument(res.ErrorCode, res.ErrorDescription); return(HttpStatusCode.InternalServerError); } // Check output parameters IList <DvArgument> formalArguments = action.OutArguments; if (outParameterValues.Count != formalArguments.Count) { result = CreateFaultDocument(501, "Action Failed"); return(HttpStatusCode.InternalServerError); } IList <OutParameter> outParams = formalArguments.Select((t, i) => new OutParameter(t, outParameterValues[i])).ToList(); result = CreateResultDocument(action, outParams, !subscriberSupportsUPnP11); return(HttpStatusCode.OK); } catch (Exception e) { string message = "Error handling SOAP request: " + e.Message; UPnPConfiguration.LOGGER.Warn(message); // Don't log the whole exception; it's only a communication error with a client result = CreateFaultDocument(500, message); // Also send message to client return(HttpStatusCode.InternalServerError); } }