using System;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using WebDAVSharp.Server.Adapters;
using WebDAVSharp.Server.Exceptions;
using WebDAVSharp.Server.Stores;
using static System.String;
namespace WebDAVSharp.Server
{
///
/// This class holds extension methods for various types related to WebDAV#.
///
internal static class WebDavExtensions
{
private static readonly Regex TokenRegex = new Regex(@".*)>");
///
/// Gets the Uri to the parent object.
///
/// The of a resource, for which the parent Uri should be retrieved.
///
/// The parent .
///
/// uri
/// Cannot get parent of root
/// is null.
/// has no parent, it refers to a root resource.
public static Uri GetParentUri(this Uri uri)
{
if (uri == null)
throw new ArgumentNullException(nameof(uri));
if (uri.Segments.Length == 1)
throw new InvalidOperationException("Cannot get parent of root");
string url = uri.ToString();
int index = url.Length - 1;
if (url[index] == '/')
index--;
while (url[index] != '/')
index--;
return new Uri(url.Substring(0, index + 1));
}
///
/// Sends a simple response with a specified HTTP status code but no content.
///
/// The to send the response through.
/// The HTTP status code for the response.
/// context
/// is null.
public static void SendSimpleResponse(this IHttpListenerContext context, int statusCode = (int) HttpStatusCode.OK)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
context.Response.StatusCode = statusCode;
context.Response.StatusDescription = HttpWorkerRequest.GetStatusDescription(statusCode);
context.Response.Close();
}
///
/// Gets the prefix that matches the specified .
///
/// The to find the most specific prefix for.
///
/// The
/// that hosts the WebDAV server and holds the collection
/// of known prefixes.
///
///
/// The most specific for the given .
///
/// Unable to find correct server root
///
/// specifies a that is not
/// known to the .
///
public static Uri GetPrefixUri(this Uri uri, WebDavServer server)
{
string url = uri.ToString();
string exactPrefix = server.Listener.Prefixes
.FirstOrDefault(item => url.StartsWith(item, StringComparison.OrdinalIgnoreCase));
if (!IsNullOrEmpty(exactPrefix))
{
return new Uri(exactPrefix);
}
string wildcardUrl = new UriBuilder(uri)
{
Host = "WebDAVSharpSpecialHostTag"
}
.ToString().Replace("WebDAVSharpSpecialHostTag", "*");
string wildcardPrefix = server.Listener.Prefixes
.FirstOrDefault(item => wildcardUrl.StartsWith(item, StringComparison.OrdinalIgnoreCase));
if (!IsNullOrEmpty(wildcardPrefix))
{
return new Uri(wildcardPrefix.Replace("://*", $"://{uri.Host}"));
}
throw new WebDavInternalServerException("Unable to find correct server root");
}
///
/// Retrieves a store item through the specified
/// from the
/// specified
/// and
/// .
///
/// The to retrieve the store item for.
/// The that hosts the .
/// The from which to retrieve the store item.
///
/// The retrieved store item.
///
///
///
/// is null.
///
///
/// is null.
///
///
/// is null.
///
///
/// If the item was not found.
///
/// refers to a document in a collection, where the
/// collection does not exist.
///
/// refers to a document that does not exist.
public static IWebDavStoreItem GetItem(this Uri uri, WebDavServer server, IWebDavStore store)
{
if (uri == null)
throw new ArgumentNullException(nameof(uri));
if (server == null)
throw new ArgumentNullException(nameof(server));
if (store == null)
throw new ArgumentNullException(nameof(store));
Uri prefixUri = uri.GetPrefixUri(server);
IWebDavStoreCollection collection = store.Root;
IWebDavStoreItem item = null;
if (prefixUri.Segments.Length == uri.Segments.Length)
return collection;
for (int index = prefixUri.Segments.Length; index < uri.Segments.Length; index++)
{
string segmentName = Uri.UnescapeDataString(uri.Segments[index]);
IWebDavStoreItem nextItem = collection.GetItemByName(segmentName.TrimEnd('/', '\\'));
if (nextItem == null)
throw new WebDavNotFoundException(); //throw new WebDavConflictException();
if (index == uri.Segments.Length - 1)
item = nextItem;
else
{
collection = nextItem as IWebDavStoreCollection;
if (collection == null)
throw new WebDavNotFoundException();
}
}
if (item == null)
throw new WebDavNotFoundException();
return item;
}
private static string Match(Regex regex, string html, int i = 1)
{
return regex.Match(html).Groups[i].Value.Trim();
}
public static Guid? GetLockTokenHeader(this IHttpListenerRequest request)
{
if (!request.Headers.AllKeys.Contains("Lock-Token"))
return null;
string r = Match(TokenRegex, request.Headers["Lock-Token"]);
if (IsNullOrEmpty(r))
return null;
return new Guid(r);
}
public static Guid? GetLockTokenIfHeader(this IHttpListenerRequest request)
{
if (!request.Headers.AllKeys.Contains("If"))
return null;
string t = request.Headers["If"].Substring(2, request.Headers["If"].Length - 4);
return new Guid(t);
}
public static string ToLockToken(this Guid? token)
{
if (token == null)
throw new NullReferenceException("token");
return "urn:uuid:" + token;
}
///
/// Gets the Timeout header : Second-number
///
/// The request with the request included
///
/// The value of the Timeout header as a string
public static double? GetTimeoutHeader(this IHttpListenerRequest request, IWebDavStore store)
{
// get the value of the timeout header as a string
string timeout = request.Headers["Timeout"];
// check if the string is valid or not infinity
// if so, try to parse it to an int
if (!IsNullOrEmpty(timeout) && !timeout.Equals("infinity") && !timeout.Equals("Infinite, Second-4100000000"))
{
string num = timeout.Substring(timeout.IndexOf("Second-", StringComparison.Ordinal) + 7);
double d;
if (double.TryParse(num, out d))
{
return d;
}
}
if (timeout.Equals("infinity") && timeout.Equals("Infinite, Second-4100000000") && store.LockSystem.AllowInfiniteCheckouts)
return null;
return 345600;
}
public static void SendException(this IHttpListenerContext context, WebDavException ex)
{
context.Response.StatusCode = ex.StatusCode;
context.Response.StatusDescription = ex.StatusDescription;
if (ex.Message == context.Response.StatusDescription)
return;
byte[] buffer = Encoding.UTF8.GetBytes(ex.Message);
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.ContentLength64 = buffer.Length;
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
context.Response.OutputStream.Flush();
}
}
}