internal async Task ProcessRequestAsync(HttpContext httpContext, ODataRequest odataRequest) { httpContext.SetODataRequest(odataRequest); var request = httpContext.Request; var httpMethod = request.Method; var inputStream = request.Body; ODataWriter odataWriter = null; try { Content content; if (odataRequest == null) { odataWriter = new ODataJsonWriter(); throw new ODataException("The Request is not an OData request.", ODataExceptionCode.RequestError); } odataWriter = ODataWriter.Create(httpContext, odataRequest); if (odataWriter == null) { odataWriter = new ODataJsonWriter(); odataWriter.Initialize(odataRequest); throw new ODataException(ODataExceptionCode.InvalidFormatParameter); } odataWriter.Initialize(odataRequest); var requestError = odataRequest.RequestError; if (requestError != null) { var innerOdataError = requestError as ODataException; var message = "An error occured during request parsing. " + requestError.Message + " See inner exception for details."; var code = innerOdataError?.ODataExceptionCode ?? ODataExceptionCode.RequestError; throw new ODataException(message, code, requestError); } odataRequest.Format = odataWriter.FormatName; var requestedContent = LoadContentByVersionRequest(odataRequest.RepositoryPath, httpContext); var exists = requestedContent != null; if (!exists && !odataRequest.IsServiceDocumentRequest && !odataRequest.IsMetadataRequest && !AllowedMethodNamesWithoutContent.Contains(httpMethod)) { ContentNotFound(httpContext); return; } JObject model; switch (httpMethod) { case "GET": if (odataRequest.IsServiceDocumentRequest) { await odataWriter.WriteServiceDocumentAsync(httpContext, odataRequest) .ConfigureAwait(false); } else if (odataRequest.IsMetadataRequest) { await odataWriter.WriteMetadataAsync(httpContext, odataRequest) .ConfigureAwait(false); } else { if (!Node.Exists(odataRequest.RepositoryPath)) { ContentNotFound(httpContext); } else if (odataRequest.IsCollection) { await odataWriter.WriteChildrenCollectionAsync(odataRequest.RepositoryPath, httpContext, odataRequest) .ConfigureAwait(false); } else if (odataRequest.IsMemberRequest) { await odataWriter.WriteContentPropertyAsync( odataRequest.RepositoryPath, odataRequest.PropertyName, odataRequest.IsRawValueRequest, httpContext, odataRequest, _appConfig) .ConfigureAwait(false); } else { await odataWriter.WriteSingleContentAsync(requestedContent, httpContext) .ConfigureAwait(false); } } break; case "PUT": // update if (odataRequest.IsMemberRequest) { throw new ODataException("Cannot access a member with HTTP PUT.", ODataExceptionCode.IllegalInvoke); } else { model = await ReadToJsonAsync(httpContext).ConfigureAwait(false); content = LoadContentOrVirtualChild(odataRequest); if (content == null) { ContentNotFound(httpContext); return; } ResetContent(content); UpdateContent(content, model, odataRequest); await odataWriter.WriteSingleContentAsync(content, httpContext) .ConfigureAwait(false); } break; case "MERGE": case "PATCH": // update if (odataRequest.IsMemberRequest) { throw new ODataException( String.Concat("Cannot access a member with HTTP ", httpMethod, "."), ODataExceptionCode.IllegalInvoke); } else { model = await ReadToJsonAsync(httpContext).ConfigureAwait(false); content = LoadContentOrVirtualChild(odataRequest); if (content == null) { ContentNotFound(httpContext); return; } UpdateContent(content, model, odataRequest); await odataWriter.WriteSingleContentAsync(content, httpContext) .ConfigureAwait(false); } break; case "POST": // invoke an action, create content if (odataRequest.IsMemberRequest) { // MEMBER REQUEST await odataWriter.WritePostOperationResultAsync(httpContext, odataRequest, _appConfig) .ConfigureAwait(false); } else { // CREATION if (!Node.Exists(odataRequest.RepositoryPath)) { // parent does not exist ContentNotFound(httpContext); return; } model = await ReadToJsonAsync(httpContext).ConfigureAwait(false); var newContent = CreateNewContent(model, odataRequest); await odataWriter.WriteSingleContentAsync(newContent, httpContext) .ConfigureAwait(false); } break; case "DELETE": if (odataRequest.IsMemberRequest) { throw new ODataException( String.Concat("Cannot access a member with HTTP ", httpMethod, "."), ODataExceptionCode.IllegalInvoke); } else { content = LoadContentOrVirtualChild(odataRequest); if (content != null) { var x = httpContext.Request.Query["permanent"].ToString(); if (x.Equals("true", StringComparison.OrdinalIgnoreCase)) { content.DeletePhysical(); } else { content.Delete(); } } } break; } } catch (ContentNotFoundException e) { var oe = new ODataException(ODataExceptionCode.ResourceNotFound, e); await odataWriter.WriteErrorResponseAsync(httpContext, oe) .ConfigureAwait(false); } catch (ODataException e) { if (e.HttpStatusCode == 500) { SnLog.WriteException(e); } await odataWriter.WriteErrorResponseAsync(httpContext, e) .ConfigureAwait(false); } catch (AccessDeniedException e) { var oe = new ODataException(ODataExceptionCode.Forbidden, e); await odataWriter.WriteErrorResponseAsync(httpContext, oe) .ConfigureAwait(false); } catch (UnauthorizedAccessException e) { var oe = new ODataException(ODataExceptionCode.Unauthorized, e); await odataWriter.WriteErrorResponseAsync(httpContext, oe) .ConfigureAwait(false); } catch (SenseNetSecurityException e) { // In case of a visitor we should not expose the information that this content actually exists. We return // a simple 404 instead to provide exactly the same response as the regular 404, where the content // really does not exist. But do this only if the visitor really does not have permission for the // requested content (because security exception could be thrown by an action or something else too). if (odataRequest != null && User.Current.Id == Identifiers.VisitorUserId) { var head = NodeHead.Get(odataRequest.RepositoryPath); if (head != null && !SecurityHandler.HasPermission(head, PermissionType.Open)) { ContentNotFound(httpContext); return; } } var oe = new ODataException(ODataExceptionCode.NotSpecified, e); SnLog.WriteException(oe); await odataWriter.WriteErrorResponseAsync(httpContext, oe) .ConfigureAwait(false); } catch (InvalidContentActionException ex) { var oe = new ODataException(ODataExceptionCode.NotSpecified, ex); if (ex.Reason != InvalidContentActionReason.NotSpecified) { oe.ErrorCode = Enum.GetName(typeof(InvalidContentActionReason), ex.Reason); } // it is unnecessary to log this exception as this is not a real error await odataWriter.WriteErrorResponseAsync(httpContext, oe) .ConfigureAwait(false); } catch (ContentRepository.Storage.Data.NodeAlreadyExistsException nae) { var oe = new ODataException(ODataExceptionCode.ContentAlreadyExists, nae); await odataWriter.WriteErrorResponseAsync(httpContext, oe) .ConfigureAwait(false); } catch (Exception ex) { var oe = new ODataException(ODataExceptionCode.NotSpecified, ex); SnLog.WriteException(oe); await odataWriter.WriteErrorResponseAsync(httpContext, oe) .ConfigureAwait(false); } }