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
}
}