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