/// <summary>
        /// Processes the OData web request. Designed for test purposes.
        /// </summary>
        /// <param name="context">An <see cref="HttpContext" /> object that provides references to the intrinsic server objects (for example, <see langword="Request" />, <see langword="Response" />, <see langword="Session" />, and <see langword="Server" />) used to service HTTP requests. </param>
        /// <param name="httpMethod">HTTP protocol method.</param>
        /// <param name="inputStream">Request stream containing the posted JSON object.</param>
        public void ProcessRequest(HttpContext context, string httpMethod, Stream inputStream)
        {
            ODataRequest   odataReq      = null;
            ODataFormatter formatter     = null;
            var            portalContext = (PortalContext)context.Items[PortalContext.CONTEXT_ITEM_KEY];

            try
            {
                Content content;

                odataReq = portalContext.ODataRequest;
                if (odataReq == null)
                {
                    formatter = ODataFormatter.Create("json", portalContext);
                    throw new ODataException("The Request is not an OData request.", ODataExceptionCode.RequestError);
                }

                this.ODataRequest = portalContext.ODataRequest;
                Exception requestError = this.ODataRequest.RequestError;

                formatter = ODataFormatter.Create(portalContext, odataReq);
                if (formatter == null)
                {
                    formatter = ODataFormatter.Create("json", portalContext);
                    throw new ODataException(ODataExceptionCode.InvalidFormatParameter);
                }

                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);
                }

                odataReq.Format = formatter.FormatName;
                formatter.Initialize(odataReq);

                var exists = Node.Exists(odataReq.RepositoryPath);
                if (!exists && !odataReq.IsServiceDocumentRequest && !odataReq.IsMetadataRequest && !AllowedMethodNamesWithoutContent.Contains(httpMethod))
                {
                    ContentNotFound(context, odataReq.RepositoryPath);
                    return;
                }

                JObject model;
                switch (httpMethod)
                {
                case "GET":
                    if (odataReq.IsServiceDocumentRequest)
                    {
                        formatter.WriteServiceDocument(portalContext, odataReq);
                    }
                    else if (odataReq.IsMetadataRequest)
                    {
                        formatter.WriteMetadata(context, odataReq);
                    }
                    else
                    {
                        if (!Node.Exists(odataReq.RepositoryPath))
                        {
                            ContentNotFound(context, odataReq.RepositoryPath);
                        }
                        else if (odataReq.IsCollection)
                        {
                            formatter.WriteChildrenCollection(odataReq.RepositoryPath, portalContext, odataReq);
                        }
                        else if (odataReq.IsMemberRequest)
                        {
                            formatter.WriteContentProperty(odataReq.RepositoryPath, odataReq.PropertyName,
                                                           odataReq.IsRawValueRequest, portalContext, odataReq);
                        }
                        else
                        {
                            formatter.WriteSingleContent(odataReq.RepositoryPath, portalContext);
                        }
                    }
                    break;

                case "PUT":     // update
                    if (odataReq.IsMemberRequest)
                    {
                        throw new ODataException("Cannot access a member with HTTP PUT.",
                                                 ODataExceptionCode.IllegalInvoke);
                    }
                    else
                    {
                        model   = Read(inputStream);
                        content = LoadContentOrVirtualChild(odataReq);
                        if (content == null)
                        {
                            ContentNotFound(context, odataReq.RepositoryPath);
                            return;
                        }

                        ResetContent(content);
                        UpdateContent(content, model, odataReq);
                        formatter.WriteSingleContent(content, portalContext);
                    }
                    break;

                case "MERGE":
                case "PATCH":     // update
                    if (odataReq.IsMemberRequest)
                    {
                        throw new ODataException(
                                  String.Concat("Cannot access a member with HTTP ", httpMethod, "."),
                                  ODataExceptionCode.IllegalInvoke);
                    }
                    else
                    {
                        model   = Read(inputStream);
                        content = LoadContentOrVirtualChild(odataReq);
                        if (content == null)
                        {
                            ContentNotFound(context, odataReq.RepositoryPath);
                            return;
                        }

                        UpdateContent(content, model, odataReq);
                        formatter.WriteSingleContent(content, portalContext);
                    }
                    break;

                case "POST":     // invoke an action, create content
                    if (odataReq.IsMemberRequest)
                    {
                        formatter.WriteOperationResult(inputStream, portalContext, odataReq);
                    }
                    else
                    {
                        // parent must exist
                        if (!Node.Exists(odataReq.RepositoryPath))
                        {
                            ContentNotFound(context, odataReq.RepositoryPath);
                            return;
                        }
                        model   = Read(inputStream);
                        content = CreateContent(model, odataReq);
                        formatter.WriteSingleContent(content, portalContext);
                    }
                    break;

                case "DELETE":
                    if (odataReq.IsMemberRequest)
                    {
                        throw new ODataException(
                                  String.Concat("Cannot access a member with HTTP ", httpMethod, "."),
                                  ODataExceptionCode.IllegalInvoke);
                    }
                    else
                    {
                        content = LoadContentOrVirtualChild(odataReq);
                        content?.Delete();
                    }
                    break;
                }
            }
            catch (ContentNotFoundException e)
            {
                var oe = new ODataException(ODataExceptionCode.ResourceNotFound, e);

                formatter?.WriteErrorResponse(context, oe);
            }
            catch (ODataException e)
            {
                if (e.HttpStatusCode == 500)
                {
                    SnLog.WriteException(e);
                }

                formatter?.WriteErrorResponse(context, e);
            }
            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 (odataReq != null && User.Current.Id == Identifiers.VisitorUserId)
                {
                    var head = NodeHead.Get(odataReq.RepositoryPath);
                    if (head != null && !SecurityHandler.HasPermission(head, PermissionType.Open))
                    {
                        ContentNotFound(context, odataReq.RepositoryPath);
                        return;
                    }
                }

                var oe = new ODataException(ODataExceptionCode.NotSpecified, e);

                SnLog.WriteException(oe);

                formatter?.WriteErrorResponse(context, oe);
            }
            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
                formatter?.WriteErrorResponse(context, oe);
            }
            catch (ContentRepository.Storage.Data.NodeAlreadyExistsException nae)
            {
                var oe = new ODataException(ODataExceptionCode.ContentAlreadyExists, nae);

                formatter?.WriteErrorResponse(context, oe);
            }
            catch (System.Threading.ThreadAbortException tae)
            {
                if (!context.Response.IsRequestBeingRedirected)
                {
                    var oe = new ODataException(ODataExceptionCode.RequestError, tae);
                    formatter?.WriteErrorResponse(context, oe);
                }
                // specific redirect response so do nothing
            }
            catch (Exception ex)
            {
                var oe = new ODataException(ODataExceptionCode.NotSpecified, ex);

                SnLog.WriteException(oe);

                formatter?.WriteErrorResponse(context, oe);
            }
            finally
            {
                context.Response.End();
            }
        }
Exemple #2
0
        public void ProcessRequest(HttpContext context, string httpMethod, Stream inputStream)
        {
            ODataRequest   odataReq      = null;
            ODataFormatter formatter     = null;
            var            portalContext = (PortalContext)context.Items[PortalContext.CONTEXT_ITEM_KEY];

            try
            {
                // Allows browsers to send cross-domain requests to this URL
                context.Response.AddHeader("Access-Control-Allow-Origin", "*");

                Content content;

                Exception requestError = null;
                try
                {
                    odataReq          = ODataRequest.Parse(portalContext.RequestedUri.GetComponents(UriComponents.Path, UriFormat.Unescaped), portalContext);
                    this.ODataRequest = odataReq;
                }
                catch (Exception e)
                {
                    requestError = e;
                }

                formatter = ODataFormatter.Create(portalContext, odataReq);
                if (formatter == null)
                {
                    formatter = ODataFormatter.Create("json", portalContext);
                    throw new ODataException(ODataExceptionCode.InvalidFormatParameter);
                }

                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 == null ? ODataExceptionCode.RequestError : innerOdataError.ODataExceptionCode;
                    throw new ODataException(message, code, requestError);
                }

                odataReq.Format = formatter.FormatName;
                formatter.Initialize(odataReq);

                var exists = Node.Exists(odataReq.RepositoryPath);
                if (httpMethod != "POST" && !exists)
                {
                    ContentNotFound(context, odataReq.RepositoryPath);
                    return;
                }

                JObject model = null;
                switch (httpMethod)
                {
                case "GET":
                    if (odataReq.IsServiceDocumentRequest)
                    {
                        formatter.WriteServiceDocument(portalContext, odataReq);
                    }
                    else if (odataReq.IsMetadataRequest)
                    {
                        formatter.WriteMetadata(context, odataReq);
                    }
                    else
                    {
                        if (!Node.Exists(odataReq.RepositoryPath))
                        {
                            ContentNotFound(context, odataReq.RepositoryPath);
                        }
                        if (odataReq.HasContentQuery)
                        {
                            formatter.WriteQueryResult(portalContext, odataReq);
                        }
                        else if (odataReq.IsCollection)
                        {
                            formatter.WriteChildrenCollection(odataReq.RepositoryPath, portalContext, odataReq);
                        }
                        else if (odataReq.IsMemberRequest)
                        {
                            formatter.WriteContentProperty(odataReq.RepositoryPath, odataReq.PropertyName, odataReq.IsRawValueRequest, portalContext, odataReq);
                        }
                        else
                        {
                            formatter.WriteSingleContent(odataReq.RepositoryPath, portalContext);
                        }
                    }
                    break;

                case "PUT":     // update
                    if (odataReq.IsMemberRequest)
                    {
                        throw new ODataException("Cannot access a member with HTTP PUT.", ODataExceptionCode.IllegalInvoke);
                    }
                    else
                    {
                        model   = Read(inputStream);
                        content = Content.Load(odataReq.RepositoryPath);
                        ResetContent(content);
                        UpdateContent(content, model, odataReq);
                        formatter.WriteSingleContent(content, portalContext);
                    }
                    break;

                case "MERGE":
                case "PATCH":     // update
                    if (odataReq.IsMemberRequest)
                    {
                        throw new ODataException(String.Concat("Cannot access a member with HTTP ", httpMethod, "."), ODataExceptionCode.IllegalInvoke);
                    }
                    else
                    {
                        model   = Read(inputStream);
                        content = Content.Load(odataReq.RepositoryPath);
                        UpdateContent(content, model, odataReq);
                        formatter.WriteSingleContent(content, portalContext);
                    }
                    break;

                case "POST":     // invoke an action, create content
                    if (odataReq.IsMemberRequest)
                    {
                        formatter.WriteOperationResult(inputStream, portalContext, odataReq);
                    }
                    else
                    {
                        model   = Read(inputStream);
                        content = CreateContent(model, odataReq, portalContext);
                        formatter.WriteSingleContent(content, portalContext);
                    }
                    break;

                case "DELETE":
                    if (odataReq.IsMemberRequest)
                    {
                        throw new ODataException(String.Concat("Cannot access a member with HTTP ", httpMethod, "."), ODataExceptionCode.IllegalInvoke);
                    }
                    else
                    {
                        //model = Read(inputStream);
                        Content.Delete(odataReq.RepositoryPath);
                    }
                    break;
                }
            }
            catch (ContentNotFoundException e)
            {
                var oe = new ODataException(ODataExceptionCode.ResourceNotFound, e);

                formatter.WriteErrorResponse(context, oe);
            }
            catch (ODataException e)
            {
                if (e.HttpStatusCode == 500)
                {
                    Logger.WriteException(e);
                }

                formatter.WriteErrorResponse(context, e);
            }
            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 (odataReq != null && User.Current.Id == User.Visitor.Id)
                {
                    var head = NodeHead.Get(odataReq.RepositoryPath);
                    if (head != null && !SecurityHandler.HasPermission(head, PermissionType.Open))
                    {
                        ContentNotFound(context, odataReq.RepositoryPath);
                        return;
                    }
                }

                var oe = new ODataException(ODataExceptionCode.NotSpecified, e);

                Logger.WriteException(oe);

                formatter.WriteErrorResponse(context, oe);
            }
            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
                //Logger.WriteException(oe);

                formatter.WriteErrorResponse(context, oe);
            }
            catch (Exception ex)
            {
                var oe = new ODataException(ODataExceptionCode.NotSpecified, ex);

                Logger.WriteException(oe);

                formatter.WriteErrorResponse(context, oe);
            }
            finally
            {
                context.Response.End();
            }
        }