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); } }
internal static IEnumerable <ODataActionItem> GetActionItems(Content content, ODataRequest request, HttpContext httpContext) { return(GetActionsWithScenario(content, request, httpContext).Select(a => new ODataActionItem { Name = a.Action.Name, DisplayName = SNSR.GetString(a.Action.Text), Icon = a.Action.Icon, Index = a.Action.Index, Url = a.Action.Uri, Forbidden = a.Action.Forbidden, IsODataAction = a.Action.IsODataOperation, ActionParameters = a.Action.ActionParameters.Select(p => p.Name).ToArray(), Scenario = a.Scenario })); }
/// <summary> /// Adds the OData request object to the items of HttpContext. /// </summary> internal static void SetODataRequest(this HttpContext httpContext, ODataRequest odataRequest) { httpContext.Items[ODataMiddleware.ODataRequestHttpContextKey] = odataRequest; }
internal static IEnumerable <ActionBase> GetActions(Content content, ODataRequest request, HttpContext httpContext) { return(ODataMiddleware.ActionResolver.GetActions(content, request?.Scenario, null, httpContext)); }
private static IEnumerable <ScenarioAction> GetActionsWithScenario(Content content, ODataRequest request, HttpContext httpContext) { var scenario = request?.Scenario; var actions = ActionFramework.GetActions(content, scenario, null, null); return(actions.Select(action => new ScenarioAction { Action = action, Scenario = scenario })); }
internal static ODataRequest Parse(HttpContext httpContext) { var path = httpContext.Request.Path.Value; var req = new ODataRequest(); try { var relPath = path.Substring(path.IndexOf(Configuration.Services.ODataServiceToken, StringComparison.OrdinalIgnoreCase) + Configuration.Services.ODataServiceToken.Length); req.IsServiceDocumentRequest = relPath.Length == 0; var segments = relPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); var resSegments = new List <string>(); var prmSegments = new List <string>(); req.IsCollection = true; for (var i = 0; i < segments.Length; i++) { if (String.Compare(segments[i], "$metadata", StringComparison.OrdinalIgnoreCase) == 0) { req.IsMetadataRequest = true; break; } if (String.Compare(segments[i], "$value", StringComparison.OrdinalIgnoreCase) == 0) { req.IsRawValueRequest = true; break; } if (String.Compare(segments[i], "$count", StringComparison.OrdinalIgnoreCase) == 0) { req.CountOnly = true; break; } if (!req.IsCollection) { prmSegments.Add(segments[i]); continue; } var segment = segments[i]; if (i == 0 && segment.StartsWith("content(", StringComparison.OrdinalIgnoreCase) && segment.EndsWith(")")) { var idStr = segment.Substring(8).Trim('(', ')'); if (idStr[0] != '\'' && idStr[idStr.Length - 1] != '\'') { int id; if (!int.TryParse(idStr, out id)) { throw new ODataException(SNSR.Exceptions.OData.InvalidId, ODataExceptionCode.InvalidId); } req.IsCollection = false; req.RequestedContentId = id; resSegments.Add(segment); continue; } } if (!segment.EndsWith("')")) { resSegments.Add(segment); } else { req.IsCollection = false; var ii = segment.IndexOf("('"); var entityName = segment.Substring(ii).Trim('(', ')').Trim('\''); segment = segment.Substring(0, ii); if (segment.Length > 0) { resSegments.Add(segment); } resSegments.Add(entityName); } } if (resSegments.Count == 0) { req.IsCollection = true; } else { if (prmSegments.Count > 0) { req.IsMemberRequest = true; req.PropertyName = prmSegments[0]; } } Content content; if (req.RequestedContentId > 0 && (content = SystemAccount.Execute(() => Content.Load(req.RequestedContentId))) != null) { req.RepositoryPath = content.Path; } else { var newPath = String.Concat("/", String.Join("/", resSegments)); req.RepositoryPath = newPath; } req.ParseQuery(path, httpContext); } catch (Exception e) { req.RequestError = e; } return(req); }
private Content CreateNewContent(JObject model, ODataRequest odataRequest) { var contentTypeName = GetPropertyValue <string>("__ContentType", model); var templateName = GetPropertyValue <string>("__ContentTemplate", model); var name = GetPropertyValue <string>("Name", model); if (string.IsNullOrEmpty(name)) { var displayName = GetPropertyValue <string>("DisplayName", model); name = ContentNamingProvider.GetNameFromDisplayName(displayName); } else { // do not allow saving a content with unencoded name name = ContentNamingProvider.GetNameFromDisplayName(name); } var parent = Node.Load <GenericContent>(odataRequest.RepositoryPath); if (string.IsNullOrEmpty(contentTypeName)) { var allowedChildTypeNames = parent.GetAllowedChildTypeNames(); if (allowedChildTypeNames is AllContentTypeNames) { contentTypeName = typeof(ContentRepository.File).Name; } else { var allowedContentTypeNames = parent.GetAllowedChildTypeNames().ToArray(); contentTypeName = allowedContentTypeNames.FirstOrDefault(); if (string.IsNullOrEmpty(contentTypeName)) { contentTypeName = typeof(ContentRepository.File).Name; } } } Content content; Node template = null; if (templateName != null) { template = ContentTemplate.GetNamedTemplate(contentTypeName, templateName); } if (template == null) { content = Content.CreateNew(contentTypeName, parent, name); } else { var node = ContentTemplate.CreateFromTemplate(parent, template, name); content = Content.Create(node); } UpdateFields(content, model); if (odataRequest.MultistepSave) { content.Save(SavingMode.StartMultistepSave); } else { content.Save(); } return(content); }
protected string GetRichTextOutput(string fieldName, RichTextFieldValue rtfValue, ODataRequest oDataRequest) { if (!oDataRequest.HasExpandedRichTextField) { return(rtfValue.Text); } return(oDataRequest.AllRichTextFieldExpanded || oDataRequest.ExpandedRichTextFields.Contains(fieldName) ? JsonConvert.SerializeObject(rtfValue) : rtfValue.Text); }