using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using System.Web; using System.Xml; using Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31.Adapters; using Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31.Exceptions; using Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31.Stores; using Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31.Utilities; namespace Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31.MethodHandlers { /// /// This class implements the PROPFIND HTTP method for WebDAV#. /// internal class WebDavPropfindMethodHandler : WebDavMethodHandlerBase, IWebDavMethodHandler { private List _requestedProperties; private Uri _requestUri; private List _webDavStoreItems; /// /// Gets the collection of the names of the HTTP methods handled by this instance. /// /// /// The names. /// public IEnumerable Names => new[] { "PROPFIND" }; /// /// Processes the request. /// /// The through which the request came in from the client. /// /// The /// object containing both the request and response /// objects to use. /// /// The that the is hosting. /// public void ProcessRequest(WebDavServer server, IHttpListenerContext context, IWebDavStore store) { /*************************************************************************************************** * Retreive all the information from the request ***************************************************************************************************/ // Read the headers, ... var isPropname = false; var depth = GetDepthHeader(context.Request); _requestUri = GetRequestUri(context.Request.Url.ToString()); try { _webDavStoreItems = GetWebDavStoreItems(context.Request.Url.GetItem(server, store), depth); } catch (UnauthorizedAccessException) { throw new WebDavUnauthorizedException(); } // Get the XmlDocument from the request var requestDoc = GetXmlDocument(context.Request); // See what is requested _requestedProperties = new List(); if (requestDoc.DocumentElement != null) { if (requestDoc.DocumentElement.LocalName != "propfind") { } else { var n = requestDoc.DocumentElement.FirstChild; if (n == null) { } else { switch (n.LocalName) { case "allprop": _requestedProperties = GetAllProperties(); break; case "propname": isPropname = true; _requestedProperties = GetAllProperties(); break; case "prop": foreach (XmlNode child in n.ChildNodes) _requestedProperties.Add(new WebDavProperty(child.LocalName, "", child.NamespaceURI)); break; default: _requestedProperties.Add(new WebDavProperty(n.LocalName, "", n.NamespaceURI)); break; } } } } else _requestedProperties = GetAllProperties(); /*************************************************************************************************** * Create the body for the response ***************************************************************************************************/ var responseDoc = ResponseDocument(context, isPropname); /*************************************************************************************************** * Send the response ***************************************************************************************************/ SendResponse(context, responseDoc); } #region SendResponse /// /// Sends the response /// /// The containing the response /// The containing the response body private static void SendResponse(IHttpListenerContext context, XmlDocument responseDocument) { // convert the XmlDocument var responseBytes = Encoding.UTF8.GetBytes(responseDocument.InnerXml); // HttpStatusCode doesn't contain WebDav status codes, but HttpWorkerRequest can handle these WebDav status codes context.Response.StatusCode = (int) WebDavStatusCode.MultiStatus; context.Response.StatusDescription = HttpWorkerRequest.GetStatusDescription((int) WebDavStatusCode.MultiStatus); context.Response.ContentLength64 = responseBytes.Length; context.Response.AdaptedInstance.ContentType = "text/xml"; context.Response.OutputStream.Write(responseBytes, 0, responseBytes.Length); context.Response.Close(); } #endregion #region RetrieveInformation /// /// Get the URI to the location /// If no slash at the end of the URI, this method adds one /// /// The that contains the URI /// /// The that contains the given uri /// private static Uri GetRequestUri(string uri) { return new Uri(uri.EndsWith("/") ? uri : uri + "/"); } /// /// Convert the given /// to a /// of /// /// This list depends on the "Depth" header /// /// The that needs to be converted /// The "Depth" header /// /// A of /// /// private static List GetWebDavStoreItems(IWebDavStoreItem iWebDavStoreItem, int depth) { var list = new List(); //IWebDavStoreCollection // if the item is a collection var collection = iWebDavStoreItem as IWebDavStoreCollection; if (collection != null) { list.Add(collection); if (depth == 0) return list; foreach (var item in collection.Items) { try { list.Add(item); } catch (Exception ex) { Debug.Print(ex.ToString()); } } return list; } // if the item is not a document, throw conflict exception if (!(iWebDavStoreItem is IWebDavStoreDocument)) throw new WebDavConflictException(); // add the item to the list list.Add(iWebDavStoreItem); return list; } /// /// Reads the XML body of the /// /// and converts it to an /// /// /// The /// /// The that contains the request body /// private XmlDocument GetXmlDocument(IHttpListenerRequest request) { try { var reader = new StreamReader(request.InputStream, Encoding.UTF8); var requestBody = reader.ReadToEnd(); reader.Close(); if (!string.IsNullOrEmpty(requestBody)) { var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(requestBody); return xmlDocument; } } catch (Exception) { } return new XmlDocument(); } /// /// Adds the standard properties for an Propfind allprop request to a of /// /// /// /// The list with all the /// private List GetAllProperties() { var list = new List { new WebDavProperty("creationdate"), new WebDavProperty("displayname"), new WebDavProperty("getcontentlength"), new WebDavProperty("getcontenttype"), new WebDavProperty("getetag"), new WebDavProperty("getlastmodified"), new WebDavProperty("resourcetype"), new WebDavProperty("supportedlock"), new WebDavProperty("ishidden") }; //list.Add(new WebDAVProperty("getcontentlanguage")); //list.Add(new WebDAVProperty("lockdiscovery")); return list; } #endregion #region BuildResponseBody /// /// Builds the containing the response body /// /// The /// The boolean defining the Propfind propname request /// /// The containing the response body /// private XmlDocument ResponseDocument(IHttpListenerContext context, bool propname) { // Create the basic response XmlDocument var responseDoc = new XmlDocument(); const string responseXml = ""; responseDoc.LoadXml(responseXml); // Generate the manager var manager = new XmlNamespaceManager(responseDoc.NameTable); manager.AddNamespace("D", "DAV:"); manager.AddNamespace("Office", "schemas-microsoft-com:office:office"); manager.AddNamespace("Repl", "http://schemas.microsoft.com/repl/"); manager.AddNamespace("Z", "urn:schemas-microsoft-com:"); var count = 0; foreach (var webDavStoreItem in _webDavStoreItems) { // Create the response element var responseProperty = new WebDavProperty("response", ""); var responseElement = responseProperty.ToXmlElement(responseDoc); // The href element Uri result; if (count == 0) { Uri.TryCreate(_requestUri, "", out result); } else { Uri.TryCreate(_requestUri, webDavStoreItem.Name, out result); } var hrefProperty = new WebDavProperty("href", result.AbsoluteUri); responseElement.AppendChild(hrefProperty.ToXmlElement(responseDoc)); count++; // The propstat element var propstatProperty = new WebDavProperty("propstat", ""); var propstatElement = propstatProperty.ToXmlElement(responseDoc); // The prop element var propProperty = new WebDavProperty("prop", ""); var propElement = propProperty.ToXmlElement(responseDoc); foreach (var davProperty in _requestedProperties) { propElement.AppendChild(PropChildElement(davProperty, responseDoc, webDavStoreItem, propname)); } // Add the prop element to the propstat element propstatElement.AppendChild(propElement); // The status element var statusProperty = new WebDavProperty("status", "HTTP/1.1 " + context.Response.StatusCode + " " + HttpWorkerRequest.GetStatusDescription(context.Response.StatusCode)); propstatElement.AppendChild(statusProperty.ToXmlElement(responseDoc)); // Add the propstat element to the response element responseElement.AppendChild(propstatElement); // Add the response element to the multistatus element responseDoc.DocumentElement.AppendChild(responseElement); } return responseDoc; } /// /// Gives the /// of a /// /// with or without values /// or with or without child elements /// /// The /// The containing the response body /// The /// The boolean defining the Propfind propname request /// /// The of the containing a value or child elements /// private XmlElement PropChildElement(WebDavProperty webDavProperty, XmlDocument xmlDocument, IWebDavStoreItem iWebDavStoreItem, bool isPropname) { // If Propfind request contains a propname element if (isPropname) { webDavProperty.Value = string.Empty; return webDavProperty.ToXmlElement(xmlDocument); } // If not, add the values to webDavProperty webDavProperty.Value = GetWebDavPropertyValue(iWebDavStoreItem, webDavProperty); var xmlElement = webDavProperty.ToXmlElement(xmlDocument); // If the webDavProperty is the resourcetype property // and the webDavStoreItem is a collection // add the collection XmlElement as a child to the xmlElement if (webDavProperty.Name != "resourcetype" || !iWebDavStoreItem.IsCollection) return xmlElement; var collectionProperty = new WebDavProperty("collection", ""); xmlElement.AppendChild(collectionProperty.ToXmlElement(xmlDocument)); return xmlElement; } /// /// Gets the correct value for a /// /// The defines the values /// The that needs a value /// /// A containing the value /// private string GetWebDavPropertyValue(IWebDavStoreItem webDavStoreItem, WebDavProperty davProperty) { switch (davProperty.Name) { case "creationdate": return webDavStoreItem.CreationDate.ToUniversalTime().ToString("s") + "Z"; case "displayname": return webDavStoreItem.Name; case "getcontentlanguage": // still to implement !!! return string.Empty; case "getcontentlength": return !webDavStoreItem.IsCollection ? "" + ((IWebDavStoreDocument) webDavStoreItem).Size : ""; case "getcontenttype": return !webDavStoreItem.IsCollection ? "" + ((IWebDavStoreDocument) webDavStoreItem).MimeType : ""; case "getetag": return !webDavStoreItem.IsCollection ? "" + ((IWebDavStoreDocument) webDavStoreItem).Etag : ""; case "getlastmodified": return webDavStoreItem.ModificationDate.ToUniversalTime().ToString("R"); case "lockdiscovery": // still to implement !!! return string.Empty; case "resourcetype": return ""; case "supportedlock": // still to implement !!! return ""; //webDavProperty.Value = ""; case "ishidden": return "" + webDavStoreItem.Hidden; default: return string.Empty; } } #endregion } }