예제 #1
0
        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);
            }
        }