/ToMigrate/Raven.Database/Server/WebApi/Filters/RavenExceptionFilterAttribute.cs

https://github.com/fitzchak/ravendb · C# · 275 lines · 232 code · 36 blank · 7 comment · 9 complexity · f00856df2adc3fff8889ed1138f71f39 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Net.Http;
  9. using System.Web.Http.Filters;
  10. using System.Web.Http.Results;
  11. using Jint.Runtime;
  12. using Lucene.Net.Search;
  13. using Raven.Abstractions.Connection;
  14. using Raven.Abstractions.Data;
  15. using Raven.Abstractions.Exceptions;
  16. using Raven.Abstractions.Exceptions.Subscriptions;
  17. using Raven.Abstractions.FileSystem;
  18. using Raven.Abstractions.Util;
  19. using Raven.Database.FileSystem.Controllers;
  20. using Raven.Json.Linq;
  21. namespace Raven.Database.Server.WebApi.Filters
  22. {
  23. public class RavenExceptionFilterAttribute : ExceptionFilterAttribute
  24. {
  25. private static readonly Dictionary<Type, Action<HttpActionExecutedContext, Exception>> handlers =
  26. new Dictionary<Type, Action<HttpActionExecutedContext, Exception>>
  27. {
  28. {typeof (BadRequestException), (ctx, e) => HandleBadRequest(ctx, e as BadRequestException)},
  29. {typeof (ConcurrencyException), (ctx, e) => HandleConcurrencyException(ctx, e as ConcurrencyException)},
  30. {typeof (JavaScriptException), (ctx, e) => HandleJintException(ctx, e as JavaScriptException)},
  31. {typeof (IndexDisabledException), (ctx, e) => HandleIndexDisabledException(ctx, e as IndexDisabledException)},
  32. {typeof (IndexDoesNotExistsException), (ctx, e) => HandleIndexDoesNotExistsException(ctx, e as IndexDoesNotExistsException)},
  33. {typeof (ImplicitFetchFieldsFromDocumentNotAllowedException), (ctx, e) => HandleImplicitFetchFieldsFromDocumentNotAllowedException(ctx, e as ImplicitFetchFieldsFromDocumentNotAllowedException)},
  34. {typeof (SynchronizationException), (ctx, e) => HandleSynchronizationException(ctx, e as SynchronizationException)},
  35. {typeof (FileNotFoundException), (ctx, e) => HandleFileNotFoundException(ctx, e as FileNotFoundException)},
  36. {typeof (SubscriptionException), (ctx, e) => HandleSubscriptionException(ctx, e as SubscriptionException)},
  37. {typeof (BooleanQuery.TooManyClauses), (ctx, e) => HandleTooManyClausesException(ctx, e as BooleanQuery.TooManyClauses)},
  38. {typeof (OperationCanceledException), (ctx, e) => HandleOperationCanceledException(ctx, e as OperationCanceledException)}
  39. };
  40. public override void OnException(HttpActionExecutedContext ctx)
  41. {
  42. var e = ctx.Exception;
  43. var exceptionType = e.GetType();
  44. try
  45. {
  46. if (handlers.ContainsKey(exceptionType))
  47. {
  48. handlers[exceptionType](ctx, e);
  49. return;
  50. }
  51. var baseType = handlers.Keys.FirstOrDefault(t => t.IsInstanceOfType(e));
  52. if (baseType != null)
  53. {
  54. handlers[baseType](ctx, e);
  55. return;
  56. }
  57. DefaultHandler(ctx, e);
  58. }
  59. catch (Exception)
  60. {
  61. //TODO: log
  62. //logger.ErrorException("Failed to properly handle error, further error handling is ignored", e);
  63. }
  64. }
  65. public static void SerializeError(HttpActionExecutedContext ctx, object error)
  66. {
  67. if (ctx.Request.Method == HttpMethods.Head) // head request must not return a message body in the response
  68. return;
  69. ctx.Response.Content = new JsonContent(RavenJObject.FromObject(error))
  70. .WithRequest(ctx.Request);
  71. }
  72. private static void DefaultHandler(HttpActionExecutedContext ctx, Exception e)
  73. {
  74. ctx.Response = new HttpResponseMessage
  75. {
  76. StatusCode = HttpStatusCode.InternalServerError,
  77. };
  78. SerializeError(ctx, new
  79. {
  80. //ExceptionType = e.GetType().AssemblyQualifiedName,
  81. Url = ctx.Request.RequestUri.PathAndQuery,
  82. Error = e.ToString(),
  83. });
  84. }
  85. private static void HandleOperationCanceledException(HttpActionExecutedContext ctx, OperationCanceledException e)
  86. {
  87. ctx.Response = new HttpResponseMessage
  88. {
  89. StatusCode = HttpStatusCode.RequestTimeout
  90. };
  91. Stopwatch sp = ctx.Request.Properties["timer"] as Stopwatch;
  92. var elapsedMilliseconds = sp == null ? -1 : sp.ElapsedMilliseconds;
  93. SerializeError(ctx, new
  94. {
  95. Url = ctx.Request.RequestUri.PathAndQuery,
  96. Error = string.Format("Request was canceled by the server due to timeout after {0}ms", elapsedMilliseconds.ToString("#,#;;0", CultureInfo.InvariantCulture)),
  97. e.Message
  98. });
  99. }
  100. private static void HandleTooManyClausesException(HttpActionExecutedContext ctx, BooleanQuery.TooManyClauses e)
  101. {
  102. ctx.Response = new HttpResponseMessage
  103. {
  104. StatusCode = HttpStatusCode.InternalServerError,
  105. };
  106. SerializeError(ctx, new
  107. {
  108. ExceptionType = e.GetType().AssemblyQualifiedName,
  109. Error = "Exceeded maximum clause count in the query.",
  110. e.Message
  111. });
  112. }
  113. private static void HandleBadRequest(HttpActionExecutedContext ctx, BadRequestException e)
  114. {
  115. ctx.Response = new HttpResponseMessage
  116. {
  117. StatusCode = HttpStatusCode.BadRequest,
  118. };
  119. SerializeError(ctx, new
  120. {
  121. Url = ctx.Request.RequestUri.PathAndQuery,
  122. e.Message,
  123. Error = e.Message
  124. });
  125. }
  126. private static void HandleConcurrencyException(HttpActionExecutedContext ctx, ConcurrencyException e)
  127. {
  128. if (ctx.ActionContext.ControllerContext.Controller is BaseFileSystemApiController)
  129. {
  130. ctx.Response = new HttpResponseMessage
  131. {
  132. StatusCode = HttpStatusCode.MethodNotAllowed,
  133. };
  134. }
  135. else
  136. {
  137. ctx.Response = new HttpResponseMessage
  138. {
  139. StatusCode = HttpStatusCode.Conflict,
  140. };
  141. }
  142. SerializeError(ctx, new
  143. {
  144. Url = ctx.Request.RequestUri.PathAndQuery,
  145. ActualETag = e.ActualETag ?? Etag.Empty,
  146. ExpectedETag = e.ExpectedETag ?? Etag.Empty,
  147. Error = e.Message
  148. });
  149. }
  150. private static void HandleJintException(HttpActionExecutedContext ctx, JavaScriptException e)
  151. {
  152. //while (e.InnerException is JintException)
  153. //{
  154. // e = (JintException)e.InnerException;
  155. //}
  156. ctx.Response = new HttpResponseMessage
  157. {
  158. StatusCode = HttpStatusCode.BadRequest,
  159. };
  160. SerializeError(ctx, new
  161. {
  162. Url = ctx.Request.RequestUri.PathAndQuery,
  163. Error = e.Message
  164. });
  165. }
  166. private static void HandleIndexDoesNotExistsException(HttpActionExecutedContext ctx, IndexDoesNotExistsException e)
  167. {
  168. ctx.Response = new HttpResponseMessage
  169. {
  170. StatusCode = HttpStatusCode.NotFound,
  171. };
  172. SerializeError(ctx, new
  173. {
  174. Url = ctx.Request.RequestUri.PathAndQuery,
  175. Error = e.Message
  176. });
  177. }
  178. private static void HandleIndexDisabledException(HttpActionExecutedContext ctx, IndexDisabledException e)
  179. {
  180. ctx.Response = new HttpResponseMessage
  181. {
  182. StatusCode = HttpStatusCode.InternalServerError,
  183. };
  184. SerializeError(ctx, new
  185. {
  186. Url = ctx.Request.RequestUri.PathAndQuery,
  187. Error = e.Information == null ? e.ToString() : e.Information.GetErrorMessage(),
  188. });
  189. }
  190. private static void HandleImplicitFetchFieldsFromDocumentNotAllowedException(HttpActionExecutedContext ctx, ImplicitFetchFieldsFromDocumentNotAllowedException e)
  191. {
  192. ctx.Response = new HttpResponseMessage
  193. {
  194. StatusCode = HttpStatusCode.InternalServerError
  195. };
  196. SerializeError(ctx, new
  197. {
  198. Url = ctx.Request.RequestUri.PathAndQuery,
  199. Error = e.Message
  200. });
  201. }
  202. private static void HandleSynchronizationException(HttpActionExecutedContext ctx, SynchronizationException e)
  203. {
  204. ctx.Response = new HttpResponseMessage
  205. {
  206. StatusCode = (HttpStatusCode) 420
  207. };
  208. SerializeError(ctx, new
  209. {
  210. Url = ctx.Request.RequestUri.PathAndQuery,
  211. Error = e.Message
  212. });
  213. }
  214. private static void HandleFileNotFoundException(HttpActionExecutedContext ctx, FileNotFoundException e)
  215. {
  216. ctx.Response = new HttpResponseMessage
  217. {
  218. StatusCode = HttpStatusCode.NotFound
  219. };
  220. SerializeError(ctx, new
  221. {
  222. Url = ctx.Request.RequestUri.PathAndQuery,
  223. Error = e.Message
  224. });
  225. }
  226. private static void HandleSubscriptionException(HttpActionExecutedContext ctx, SubscriptionException e)
  227. {
  228. ctx.Response = new HttpResponseMessage
  229. {
  230. StatusCode = e.ResponseStatusCode
  231. };
  232. SerializeError(ctx, new
  233. {
  234. Url = ctx.Request.RequestUri.PathAndQuery,
  235. Error = e.Message
  236. });
  237. }
  238. }
  239. }