WebDAVServer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Net;
  7. using WebDAVSharp.Server.Adapters;
  8. using WebDAVSharp.Server.Adapters.AuthenticationTypes;
  9. using WebDAVSharp.Server.MethodHandlers;
  10. using WebDAVSharp.Server.Stores;
  11. using WebDAVSharp.Server.Utilities;
  12. namespace WebDAVSharp.Server
  13. {
  14. /// <summary>
  15. /// This class implements the core WebDAV server.
  16. /// </summary>
  17. public class WebDavServer : WebDavDisposableBase
  18. {
  19. #region Variables
  20. /// <summary>
  21. /// The HTTP user
  22. /// </summary>
  23. public static string HttpUser = "HTTP.User";
  24. private IHttpListener _listener;
  25. private readonly bool _ownsListener;
  26. private IWebDavStore _store;
  27. private Dictionary<string, IWebDavMethodHandler> _methodHandlers;
  28. /// <summary>
  29. /// </summary>
  30. public int DefaultConnectionLimit { get; } = 500;
  31. /// <summary>
  32. /// </summary>
  33. public bool Expect100Continue { get; } = true;
  34. /// <summary>
  35. /// </summary>
  36. public int MaxServicePoints { get; } = 500;
  37. private bool _isListening;
  38. #endregion Variables
  39. #region Properties
  40. /// <summary>
  41. /// Allow users to have Indefinite Locks
  42. /// </summary>
  43. public bool AllowInfiniteCheckouts
  44. {
  45. get => _store.LockSystem.AllowInfiniteCheckouts;
  46. set => _store.LockSystem.AllowInfiniteCheckouts = value;
  47. }
  48. /// <summary>
  49. /// The maximum number of seconds a person can check an item out for.
  50. /// </summary>
  51. public long MaxCheckOutSeconds
  52. {
  53. get => _store.LockSystem.MaxCheckOutSeconds;
  54. set => _store.LockSystem.MaxCheckOutSeconds = value;
  55. }
  56. /// <summary>
  57. /// Gets the <see cref="IWebDavStore" /> this <see cref="WebDavServer" /> is hosting.
  58. /// </summary>
  59. /// <value>
  60. /// The store.
  61. /// </value>
  62. public IWebDavStore Store => _store;
  63. /// <summary>
  64. /// Gets the
  65. /// <see cref="IHttpListener" /> that this
  66. /// <see cref="WebDavServer" /> uses for
  67. /// the web server portion.
  68. /// </summary>
  69. /// <value>
  70. /// The listener.
  71. /// </value>
  72. internal IHttpListener Listener => _listener;
  73. #endregion Properties
  74. #region Constructor
  75. ///// <summary>
  76. ///// </summary>
  77. ///// <param name="key"></param>
  78. //public delegate void ClearCaches(string key);
  79. //private void DoClearCaches(string key)
  80. //{
  81. // foreach (IWebDavMethodHandler o in _methodHandlers.Values)
  82. // o.RemoveCacheObject(key);
  83. //}
  84. /// <summary>
  85. /// </summary>
  86. /// <param name="store"></param>
  87. /// <param name="authtype"></param>
  88. /// <param name="methodHandlers"></param>
  89. public WebDavServer(ref IWebDavStore store, AuthType authtype, IEnumerable<IWebDavMethodHandler> methodHandlers = null)
  90. {
  91. ServicePointManager.DefaultConnectionLimit = DefaultConnectionLimit;
  92. ServicePointManager.Expect100Continue = Expect100Continue;
  93. ServicePointManager.MaxServicePoints = MaxServicePoints;
  94. ServicePointManager.MaxServicePointIdleTime = int.MaxValue;
  95. _ownsListener = true;
  96. switch (authtype)
  97. {
  98. case AuthType.Basic:
  99. _listener = new HttpListenerBasicAdapter();
  100. break;
  101. case AuthType.Negotiate:
  102. _listener = new HttpListenerNegotiateAdapter();
  103. break;
  104. case AuthType.Anonymous:
  105. _listener = new HttpListenerAnyonymousAdapter();
  106. break;
  107. }
  108. methodHandlers = methodHandlers ?? WebDavMethodHandlers.BuiltIn;
  109. IWebDavMethodHandler[] webDavMethodHandlers = methodHandlers as IWebDavMethodHandler[] ?? methodHandlers.ToArray();
  110. if (!webDavMethodHandlers.Any())
  111. throw new ArgumentException("The methodHandlers collection is empty", nameof(methodHandlers));
  112. if (webDavMethodHandlers.Any(methodHandler => methodHandler == null))
  113. throw new ArgumentException("The methodHandlers collection contains a null-reference", nameof(methodHandlers));
  114. _store = store;
  115. //_store.FClearCaches = DoClearCaches;
  116. var handlersWithNames =
  117. from methodHandler in webDavMethodHandlers
  118. from name in methodHandler.Names
  119. select new
  120. {
  121. name,
  122. methodHandler
  123. };
  124. _methodHandlers = handlersWithNames.ToDictionary(v => v.name, v => v.methodHandler);
  125. }
  126. /// <summary>
  127. /// This constructor uses a Negotiate Listener if one isn't passed.
  128. /// Initializes a new instance of the <see cref="WebDavServer" /> class.
  129. /// </summary>
  130. /// <param name="store">
  131. /// The
  132. /// <see cref="IWebDavStore" /> store object that will provide
  133. /// collections and documents for this
  134. /// <see cref="WebDavServer" />.
  135. /// </param>
  136. /// <param name="listener">
  137. /// The
  138. /// <see cref="IHttpListener" /> object that will handle the web server portion of
  139. /// the WebDAV server; or
  140. /// <c>null</c> to use a fresh one.
  141. /// </param>
  142. /// <param name="methodHandlers">
  143. /// A collection of HTTP method handlers to use by this
  144. /// <see cref="WebDavServer" />;
  145. /// or
  146. /// <c>null</c> to use the built-in method handlers.
  147. /// </param>
  148. /// <exception cref="System.ArgumentNullException">
  149. /// <para>
  150. /// <paramref name="listener" /> is <c>null</c>.
  151. /// </para>
  152. /// <para>- or -</para>
  153. /// <para>
  154. /// <paramref name="store" /> is <c>null</c>.
  155. /// </para>
  156. /// </exception>
  157. /// <exception cref="System.ArgumentException">
  158. /// <para>
  159. /// <paramref name="methodHandlers" /> is empty.
  160. /// </para>
  161. /// <para>- or -</para>
  162. /// <para>
  163. /// <paramref name="methodHandlers" /> contains a <c>null</c>-reference.
  164. /// </para>
  165. /// </exception>
  166. public WebDavServer(ref IWebDavStore store, IHttpListener listener = null, IEnumerable<IWebDavMethodHandler> methodHandlers = null)
  167. {
  168. ServicePointManager.DefaultConnectionLimit = DefaultConnectionLimit;
  169. ServicePointManager.Expect100Continue = Expect100Continue;
  170. ServicePointManager.MaxServicePoints = MaxServicePoints;
  171. ServicePointManager.MaxServicePointIdleTime = int.MaxValue;
  172. if (store == null)
  173. throw new ArgumentNullException(nameof(store));
  174. if (listener == null)
  175. {
  176. listener = new HttpListenerNegotiateAdapter();
  177. _ownsListener = true;
  178. }
  179. methodHandlers = methodHandlers ?? WebDavMethodHandlers.BuiltIn;
  180. IWebDavMethodHandler[] webDavMethodHandlers = methodHandlers as IWebDavMethodHandler[] ?? methodHandlers.ToArray();
  181. if (!webDavMethodHandlers.Any())
  182. throw new ArgumentException("The methodHandlers collection is empty", nameof(methodHandlers));
  183. if (webDavMethodHandlers.Any(methodHandler => methodHandler == null))
  184. throw new ArgumentException("The methodHandlers collection contains a null-reference", nameof(methodHandlers));
  185. _listener = listener;
  186. _store = store;
  187. //_store.FClearCaches = DoClearCaches;
  188. var handlersWithNames =
  189. from methodHandler in webDavMethodHandlers
  190. from name in methodHandler.Names
  191. select new
  192. {
  193. name,
  194. methodHandler
  195. };
  196. _methodHandlers = handlersWithNames.ToDictionary(v => v.name, v => v.methodHandler);
  197. }
  198. #endregion Constructor
  199. #region Functions
  200. /// <summary>
  201. /// Releases unmanaged and - optionally - managed resources
  202. /// </summary>
  203. /// <param name="disposing">
  204. /// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only
  205. /// unmanaged resources.
  206. /// </param>
  207. protected override void Dispose(bool disposing)
  208. {
  209. if (_ownsListener)
  210. _listener.Dispose();
  211. }
  212. private List<HttpReciever> _httpRecievers;
  213. /// <summary>
  214. /// Starts this
  215. /// <see cref="WebDavServer" /> and returns once it has
  216. /// been started successfully.
  217. /// </summary>
  218. /// <exception cref="System.InvalidOperationException">
  219. /// This WebDAVServer instance is already running, call to Start is
  220. /// invalid at this point
  221. /// </exception>
  222. /// <exception cref="ObjectDisposedException">This <see cref="WebDavServer" /> instance has been disposed of.</exception>
  223. /// <exception cref="InvalidOperationException">The server is already running.</exception>
  224. public void Start(String url)
  225. {
  226. Listener.Prefixes.Add(url);
  227. EnsureNotDisposed();
  228. if (_isListening)
  229. throw new InvalidOperationException("This WebDAVServer instance is already running, call to Start is invalid at this point");
  230. _isListening = true;
  231. Listener.Start();
  232. _httpRecievers = new List<HttpReciever>();
  233. for (int i = 0; i < DefaultConnectionLimit; i++)
  234. {
  235. HttpReciever hr = new HttpReciever(i.ToString(CultureInfo.InvariantCulture), ref _listener, ref _methodHandlers, ref _store, this);
  236. _httpRecievers.Add(hr);
  237. hr.Start();
  238. }
  239. }
  240. /// <summary>
  241. /// Starts this
  242. /// <see cref="WebDavServer" /> and returns once it has
  243. /// been stopped successfully.
  244. /// </summary>
  245. /// <exception cref="System.InvalidOperationException">
  246. /// This WebDAVServer instance is not running, call to Stop is invalid
  247. /// at this point
  248. /// </exception>
  249. /// <exception cref="ObjectDisposedException">This <see cref="WebDavServer" /> instance has been disposed of.</exception>
  250. /// <exception cref="InvalidOperationException">The server is not running.</exception>
  251. public void Stop()
  252. {
  253. foreach (HttpReciever httpReciever in _httpRecievers)
  254. {
  255. httpReciever.Stop();
  256. }
  257. EnsureNotDisposed();
  258. }
  259. #endregion Functions
  260. }
  261. }