using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Threading; using Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31.Adapters; using Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31.Exceptions; using Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31.MethodHandlers; using Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31.Stores; namespace Mtp2Dav.WebDAVSharp.Server._1d2086a502937936ebc6bfe19cfa15d855be1c31 { /// /// This class implements the core WebDAV server. /// public class WebDavServer : WebDavDisposableBase { /// /// The HTTP user /// public const string HttpUser = "HTTP.User"; private readonly Dictionary _methodHandlers; private readonly bool _ownsListener; private readonly object _threadLock = new object(); private ManualResetEvent _stopEvent; private Thread _thread; /// /// Initializes a new instance of the class. /// /// /// The /// store object that will provide /// collections and documents for this /// . /// /// /// The /// object that will handle the web server portion of /// the WebDAV server; or /// null to use a fresh one. /// /// /// A collection of HTTP method handlers to use by this /// ; /// or /// null to use the built-in method handlers. /// /// /// /// is null. /// /// - or - /// /// is null. /// /// /// /// /// is empty. /// /// - or - /// /// contains a null-reference. /// /// public WebDavServer(IWebDavStore store, IHttpListener listener = null, IEnumerable methodHandlers = null) { if (store == null) throw new ArgumentNullException(nameof(store)); if (listener == null) { listener = new HttpListenerAdapter(); _ownsListener = true; } methodHandlers = methodHandlers ?? WebDavMethodHandlers.BuiltIn; var webDavMethodHandlers = methodHandlers as IWebDavMethodHandler[] ?? methodHandlers.ToArray(); if (!webDavMethodHandlers.Any()) throw new ArgumentException("The methodHandlers collection is empty", nameof(methodHandlers)); if (webDavMethodHandlers.Any(methodHandler => methodHandler == null)) throw new ArgumentException("The methodHandlers collection contains a null-reference", nameof(methodHandlers)); Listener = listener; Store = store; var handlersWithNames = from methodHandler in webDavMethodHandlers from name in methodHandler.Names select new { name, methodHandler }; _methodHandlers = handlersWithNames.ToDictionary(v => v.name, v => v.methodHandler); } /// /// Gets the /// that this /// uses for /// the web server portion. /// /// /// The listener. /// internal IHttpListener Listener { get; } /// /// Gets the this is hosting. /// /// /// The store. /// public IWebDavStore Store { get; } /// /// Releases unmanaged and - optionally - managed resources /// /// /// true to release both managed and unmanaged resources; false to release only /// unmanaged resources. /// protected override void Dispose(bool disposing) { lock (_threadLock) { if (_thread != null) Stop(); } if (_ownsListener) Listener.Dispose(); } /// /// Starts this /// and returns once it has /// been started successfully. /// /// /// This WebDAVServer instance is already running, call to Start is /// invalid at this point /// /// This instance has been disposed of. /// The server is already running. public void Start(string Url) { Listener.Prefixes.Add(Url); EnsureNotDisposed(); lock (_threadLock) { if (_thread != null) { throw new InvalidOperationException( "This WebDAVServer instance is already running, call to Start is invalid at this point"); } _stopEvent = new ManualResetEvent(false); _thread = new Thread(BackgroundThreadMethod) { Name = "WebDAVServer.Thread", IsBackground = true, }; _thread.Start(); } } /// /// Starts this /// and returns once it has /// been stopped successfully. /// /// /// This WebDAVServer instance is not running, call to Stop is invalid /// at this point /// /// This instance has been disposed of. /// The server is not running. public void Stop() { EnsureNotDisposed(); lock (_threadLock) { if (_thread == null) { throw new InvalidOperationException( "This WebDAVServer instance is not running, call to Stop is invalid at this point"); } _stopEvent.Set(); _thread.Join(); _stopEvent.Close(); _stopEvent = null; _thread = null; } } /// /// The background thread method. /// private void BackgroundThreadMethod() { try { Listener.Start(); Console.WriteLine($"WebDAVServer Listening on {Listener.Prefixes.FirstOrDefault()}"); while (true) { if (_stopEvent.WaitOne(0)) return; var context = Listener.GetContext(_stopEvent); if (context == null) { return; } ThreadPool.QueueUserWorkItem(ProcessRequest, context); } } finally { Listener.Stop(); } } /// /// Processes the request. /// /// The state. /// If the method to process is not allowed /// /// If the user is unauthorized or has no /// access /// /// If the item was not found /// If a method is not yet implemented /// If the server had an internal problem private void ProcessRequest(object state) { var context = (IHttpListenerContext)state; // For authentication Thread.SetData(Thread.GetNamedDataSlot(HttpUser), context.AdaptedInstance.User.Identity); try { try { var method = context.Request.HttpMethod; IWebDavMethodHandler methodHandler; if (!_methodHandlers.TryGetValue(method, out methodHandler)) throw new WebDavMethodNotAllowedException(string.Format(CultureInfo.InvariantCulture, "%s ({0})", context.Request.HttpMethod)); context.Response.AppendHeader("DAV", "1,2,1#extend"); methodHandler.ProcessRequest(this, context, Store); } catch (WebDavException) { throw; } catch (UnauthorizedAccessException) { throw new WebDavUnauthorizedException(); } catch (FileNotFoundException ex) { throw new WebDavNotFoundException(innerException: ex); } catch (DirectoryNotFoundException ex) { throw new WebDavNotFoundException(innerException: ex); } catch (NotImplementedException ex) { throw new WebDavNotImplementedException(innerException: ex); } catch (Exception ex) { throw new WebDavInternalServerException(innerException: ex); } } catch (WebDavException ex) { context.Response.StatusCode = ex.StatusCode; context.Response.StatusDescription = ex.StatusDescription; if (ex.Message != context.Response.StatusDescription) { var 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.Close(); } } } }