/// <summary> /// Dispatch the WebDAV request based on the given HTTP context. /// </summary> /// <param name="httpContext"> /// HTTP context for this request. /// </param> /// <returns> /// A task that represents the request dispatching operation. /// </returns> public async Task DispatchRequestAsync(IHttpContext httpContext) { // Make sure a HTTP context is specified if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } // Make sure the HTTP context has a request var request = httpContext.Request; if (request == null) { throw new ArgumentException("The HTTP context doesn't have a request.", nameof(httpContext)); } // Make sure the HTTP context has a response var response = httpContext.Response; if (response == null) { throw new ArgumentException("The HTTP context doesn't have a response.", nameof(httpContext)); } // Determine the request log-string var logRequest = $"{request.HttpMethod}:{request.Url}:{request.RemoteEndPoint}"; var range = request.GetRange(); if (null != range) { logRequest += $" ({range.Start?.ToString() ?? string.Empty}-{range.End?.ToString() ?? string.Empty})"; } // Log the request s_log.Log(LogLevel.Info, () => $"{logRequest} - Start processing"); try { // Set the Server header of the response message. This has no // functional use, but it can be used to diagnose problems by // determining the actual WebDAV server and version. response.SetHeaderValue("Server", s_serverName); // Start the stopwatch var sw = Stopwatch.StartNew(); IRequestHandler requestHandler; try { // Obtain the request handler for this message requestHandler = _requestHandlerFactory.GetRequestHandler(httpContext); // Make sure we got a request handler if (requestHandler == null) { // Log warning s_log.Log(LogLevel.Warning, () => $"{logRequest} - Not implemented."); // This request is not implemented httpContext.Response.SetStatus(DavStatusCode.NotImplemented); return; } } catch (Exception exc) { // Log error s_log.Log(LogLevel.Error, $"Unexpected exception while trying to obtain the request handler (method={request.HttpMethod}, url={request.Url}, source={request.RemoteEndPoint}", exc); // Abort return; } try { // Handle the request if (await requestHandler.HandleRequestAsync(httpContext, _store).ConfigureAwait(false)) { // Log processing duration s_log.Log(LogLevel.Info, () => $"{logRequest} - Finished processing ({sw.ElapsedMilliseconds}ms, HTTP result: {httpContext.Response.Status})"); } else { // Log warning s_log.Log(LogLevel.Warning, () => $"{logRequest} - Not processed."); // Set status code to bad request httpContext.Response.SetStatus(DavStatusCode.NotImplemented); } } catch (HttpListenerException hle) when(hle.ErrorCode == ERROR_OPERATION_ABORTED) { s_log.Log(LogLevel.Error, $"Operation aborted at (method={request.HttpMethod}, url={request.Url}, source={request.RemoteEndPoint}"); } // happens when client cancel operation, usially nothing to scare catch (HttpListenerException hle) when(hle.ErrorCode == ERROR_CONNECTION_INVALID) { s_log.Log(LogLevel.Error, $"An operation was attempted on a nonexistent network connection at (method={request.HttpMethod}, url={request.Url}, source={request.RemoteEndPoint}"); } // happens when client cancel operation, usially nothing to scare catch (HttpListenerException hle) when(hle.ErrorCode == ERROR_NETNAME_DELETED) { s_log.Log(LogLevel.Error, $"The specified network name is no longer available at (method={request.HttpMethod}, url={request.Url}, source={request.RemoteEndPoint}"); } catch (HttpListenerException excListener) { if (excListener.ErrorCode != ERROR_OPERATION_ABORTED) { throw; } } catch (AggregateException aex) when(aex.InnerExceptions.Count == 1 && aex.InnerExceptions[0] is AuthenticationException auex) { var status = DavStatusCode.Unauthorized; httpContext.Response.SetStatus(status); httpContext.Response.StatusDescription = $"{status.GetStatusDescription()}: {auex.Message}"; s_log.Log(LogLevel.Error, $"Error while handling request (method={request.HttpMethod}, url={request.Url} {httpContext.Response.StatusDescription}"); } catch (Exception exc) { s_log.Log(LogLevel.Error, $"Unexpected exception while handling request (method={request.HttpMethod}, url={request.Url}, source={request.RemoteEndPoint}", exc); //, source={request.RemoteEndPoint}", exc); // request.RemoteEndPoint may be disposed try { // Attempt to return 'InternalServerError' (if still possible) httpContext.Response.SetStatus(DavStatusCode.InternalServerError); } catch { // We might not be able to send the response, because a response // was already initiated by the the request handler. } } finally { // Check if we need to dispose the request handler // ReSharper disable once SuspiciousTypeConversion.Global (requestHandler as IDisposable)?.Dispose(); } } finally { // Always close the context await httpContext.CloseAsync().ConfigureAwait(false); } }
/// <summary> /// Dispatch the WebDAV request based on the given HTTP context. /// </summary> /// <param name="httpContext"> /// HTTP context for this request. /// </param> /// <returns> /// A task that represents the request dispatching operation. /// </returns> public async Task DispatchRequestAsync(IHttpContext httpContext) { // Make sure a HTTP context is specified if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } // Make sure the HTTP context has a request var request = httpContext.Request; if (request == null) { throw new ArgumentException("The HTTP context doesn't have a request.", nameof(httpContext)); } // Make sure the HTTP context has a response var response = httpContext.Response; if (response == null) { throw new ArgumentException("The HTTP context doesn't have a response.", nameof(httpContext)); } // Determine the request log-string var logRequest = $"{request.HttpMethod}:{request.Url}:{request.RemoteEndPoint}"; // Log the request s_log.Log(LogLevel.Info, () => $"{logRequest} - Start processing"); try { // Set the Server header of the response message. This has no // functional use, but it can be used to diagnose problems by // determining the actual WebDAV server and version. response.SetHeaderValue("Server", s_serverName); // Start the stopwatch var sw = Stopwatch.StartNew(); IRequestHandler requestHandler; try { // Obtain the request handler for this message requestHandler = _requestHandlerFactory.GetRequestHandler(httpContext); // Make sure we got a request handler if (requestHandler == null) { // Log warning s_log.Log(LogLevel.Warning, () => $"{logRequest} - Not implemented."); // This request is not implemented httpContext.Response.SetStatus(DavStatusCode.NotImplemented); return; } } catch (Exception exc) { // Log error s_log.Log(LogLevel.Error, () => $"Unexpected exception while trying to obtain the request handler (method={request.HttpMethod}, url={request.Url}, source={request.RemoteEndPoint}", exc); // Abort return; } try { // Handle the request if (await requestHandler.HandleRequestAsync(httpContext, _store).ConfigureAwait(false)) { // Log processing duration s_log.Log(LogLevel.Info, () => $"{logRequest} - Finished processing ({sw.ElapsedMilliseconds}ms, HTTP result: {httpContext.Response.Status})"); } else { // Log warning s_log.Log(LogLevel.Warning, () => $"{logRequest} - Not processed."); // Set status code to bad request httpContext.Response.SetStatus(DavStatusCode.NotImplemented); } } catch (Exception exc) { // Log what's going wrong s_log.Log(LogLevel.Error, () => $"Unexpected exception while handling request (method={request.HttpMethod}, url={request.Url}, source={request.RemoteEndPoint}", exc); try { // Attempt to return 'InternalServerError' (if still possible) httpContext.Response.SetStatus(DavStatusCode.InternalServerError); } catch { // We might not be able to send the response, because a response // was already initiated by the the request handler. } } finally { // Check if we need to dispose the request handler // ReSharper disable once SuspiciousTypeConversion.Global (requestHandler as IDisposable)?.Dispose(); } } finally { // Always close the context await httpContext.CloseAsync().ConfigureAwait(false); } }