Skip to content

Commit

Permalink
Making C1PageRoute/CmsPageHttpRequest handle page preview requests
Browse files Browse the repository at this point in the history
  • Loading branch information
napernik committed Jan 8, 2020
1 parent 19841c6 commit 78b472a
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 30 deletions.
5 changes: 3 additions & 2 deletions Composite/Composite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -256,14 +256,15 @@
<Compile Include="Core\Serialization\CompositeJsonSerializer.cs" />
<Compile Include="Core\Serialization\CompositeSerializationBinder.cs" />
<Compile Include="Core\WebClient\PageStructureRpc.cs" />
<Compile Include="Core\WebClient\Renderings\Page\PagePreviewContext.cs" />
<Compile Include="Core\WebClient\Renderings\Page\IPageContentFilter.cs" />
<Compile Include="Core\WebClient\Renderings\INonCachebleRequestHostnameMapper.cs" />
<Compile Include="Core\WebClient\Services\WampRouter\WampRouteWrapper.cs" />
<Compile Include="Data\Caching\CachedTable.cs" />
<Compile Include="Data\Types\IUserGroupActiveLocale.cs" />
<Compile Include="Data\Types\VersionedDataHelperContract.cs" />
<Compile Include="Functions\IDynamicFunction.cs" />
<Compile Include="Plugins\Elements\ElementProviders\PageElementProvider\PageSearchToken.cs" />
<Compile Include="Plugins\Elements\ElementProviders\PageElementProvider\PageSearchToken.cs" />
<Compile Include="Plugins\Elements\UrlToEntityToken\WebsiteFileUrlToEntityTokenMapper.cs" />
<Compile Include="Plugins\Elements\UrlToEntityToken\MediaUrlToEntityTokenMapper.cs" />
<Compile Include="Plugins\Forms\WebChannel\UiControlFactories\TemplatedTreelSelectorUiControlFactory.cs">
Expand Down Expand Up @@ -2694,7 +2695,7 @@
</Target>
-->
<Target Name="BeforeBuild">
<PropertyGroup>
<PropertyGroup>
<GitBranchFile>$(ProjectDir)git_branch.txt</GitBranchFile>
<GitCommitHashFile>$(ProjectDir)git_commithash.txt</GitCommitHashFile>
</PropertyGroup>
Expand Down
24 changes: 20 additions & 4 deletions Composite/Core/Routing/Pages/C1PageRoute.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using System;
using System;
using System.Globalization;
using System.Web;
using System.Web.Routing;
using Composite.Core.WebClient;
using Composite.Core.Configuration;
using Composite.Core.Extensions;
using Composite.Core.WebClient.Renderings;
using Composite.Core.WebClient.Renderings.Page;
using Composite.Search.DocumentSources;

namespace Composite.Core.Routing.Pages
{
Expand Down Expand Up @@ -42,8 +45,7 @@ public static PageUrlData PageUrlData
/// <returns>The PathInfo url part.</returns>
public static string GetPathInfo()
{
var urlData = PageUrlData;
return urlData != null ? urlData.PathInfo : null;
return PageUrlData?.PathInfo;
}

/// <summary>
Expand Down Expand Up @@ -94,13 +96,22 @@ public override RouteData GetRouteData(HttpContextBase context)

string localPath = context.Request.Url.LocalPath;

var urlProvider = PageUrls.UrlProvider;
if (IsPagePreviewPath(localPath) &&
PagePreviewContext.TryGetPreviewKey(context.Request, out Guid previewKey))
{
var page = PagePreviewContext.GetPage(previewKey);
if (page == null) throw new InvalidOperationException("Not preview information found by key: " + previewKey);

return new RouteData(this, new C1PageRouteHandler(new PageUrlData(page)));
}

if (UrlUtils.IsAdminConsoleRequest(localPath) || IsRenderersPath(localPath))
{
return null;
}

var urlProvider = PageUrls.UrlProvider;

string currentUrl = context.Request.Url.OriginalString;

UrlKind urlKind;
Expand Down Expand Up @@ -195,6 +206,11 @@ private static bool IsRenderersPath(string relativeUrl)
return relativeUrl.StartsWith(UrlUtils.RenderersRootPath + "/", true);
}

private static bool IsPagePreviewPath(string relativeUrl)
{
return relativeUrl.StartsWith($"{UrlUtils.RenderersRootPath}/PagePreview", true);
}

private RouteData GetRedirectRoute(string url)
{
return new RouteData(this, new SeoFriendlyRedirectRouteHandler(url));
Expand Down
18 changes: 6 additions & 12 deletions Composite/Core/WebClient/Renderings/Page/PagePreviewBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;
using Composite.Data.Types;

namespace Composite.Core.WebClient.Renderings.Page
Expand All @@ -13,8 +12,6 @@ namespace Composite.Core.WebClient.Renderings.Page
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public class PagePreviewBuilder
{
private static readonly TimeSpan PreviewExpirationTimeSpan = new TimeSpan(0, 20, 0);

/// <summary>
/// Execute an 'im mem' preview request of the provided page and content. Requires IIS to run in "Integrated" pipeline mode.
/// </summary>
Expand All @@ -41,33 +38,30 @@ public static string RenderPreview(IPage selectedPage, IList<IPagePlaceholderCon
/// </returns>
public static string RenderPreview(IPage selectedPage, IList<IPagePlaceholderContent> contents, RenderingReason renderingReason)
{
HttpContext ctx = HttpContext.Current;
string key = Guid.NewGuid().ToString();
string query = "previewKey=" + key;

ctx.Cache.Add(key + "_SelectedPage", selectedPage, null, Cache.NoAbsoluteExpiration, PreviewExpirationTimeSpan, CacheItemPriority.NotRemovable, null);
ctx.Cache.Add(key + "_SelectedContents", contents, null, Cache.NoAbsoluteExpiration, PreviewExpirationTimeSpan, CacheItemPriority.NotRemovable, null);
ctx.Cache.Add(key + "_RenderingReason", renderingReason, null, Cache.NoAbsoluteExpiration, PreviewExpirationTimeSpan, CacheItemPriority.NotRemovable, null);

if (!HttpRuntime.UsingIntegratedPipeline)
{
throw new InvalidOperationException("IIS classic mode not supported");
}

var previewKey = Guid.NewGuid();
PagePreviewContext.Save(previewKey, selectedPage, contents, renderingReason);

// The header trick here is to work around (what seems to be) a bug in .net 4.5, where preserveForm=false is ignored
// asp.net 4.5 request validation will see the 'page edit http post' data and start bitching. It really should not.
var headers = new System.Collections.Specialized.NameValueCollection
{
{"Content-Length", "0"}
};

var ctx = HttpContext.Current;
string cookieHeader = ctx.Request.Headers["Cookie"];
if (!string.IsNullOrEmpty(cookieHeader))
{
headers.Add("Cookie", cookieHeader);
}

ctx.Server.TransferRequest("~/Renderers/Page.aspx?" + query, false, "GET", headers);
string previewPath = $"~/Renderers/PagePreview?{PagePreviewContext.PreviewKeyUrlParameter}={previewKey}";
ctx.Server.TransferRequest(previewPath, false, "GET", headers);

return String.Empty;
}
Expand Down
69 changes: 69 additions & 0 deletions Composite/Core/WebClient/Renderings/Page/PagePreviewContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web;
using System.Web.Caching;
using Composite.Data.Types;

namespace Composite.Core.WebClient.Renderings.Page
{
internal static class PagePreviewContext
{
public static readonly string PreviewKeyUrlParameter = "previewKey";

private static readonly TimeSpan PreviewExpirationTimeSpan = new TimeSpan(0, 20, 0);

private static string CacheKey_Page(Guid key) => key + "_SelectedPage";
private static string CacheKey_Contents(Guid key) => key + "_SelectedContents";
private static string CacheKey_RenderingReason(Guid key) => key + "_RenderingReason";

public static void Save(Guid previewKey, IPage selectedPage, IList<IPagePlaceholderContent> contents, RenderingReason renderingReason)
{
var cache = HttpRuntime.Cache;

cache.Add(CacheKey_Page(previewKey), selectedPage, null, Cache.NoAbsoluteExpiration, PreviewExpirationTimeSpan, CacheItemPriority.NotRemovable, null);
cache.Add(CacheKey_Contents(previewKey), contents, null, Cache.NoAbsoluteExpiration, PreviewExpirationTimeSpan, CacheItemPriority.NotRemovable, null);
cache.Add(CacheKey_RenderingReason(previewKey), renderingReason, null, Cache.NoAbsoluteExpiration, PreviewExpirationTimeSpan, CacheItemPriority.NotRemovable, null);
}

public static bool TryGetPreviewKey(HttpRequest request, out Guid previewKey)
{
return TryGetPreviewKey(request.QueryString, out previewKey);
}

public static bool TryGetPreviewKey(HttpRequestBase request, out Guid previewKey)
{
return TryGetPreviewKey(request.QueryString, out previewKey);
}

private static bool TryGetPreviewKey(NameValueCollection queryString, out Guid previewKey)
{
var value = queryString[PreviewKeyUrlParameter];
if (!string.IsNullOrWhiteSpace(value) && Guid.TryParse(value, out previewKey))
{
return true;
}

previewKey = Guid.Empty;
return false;
}

public static IPage GetPage(Guid previewKey)
=> (IPage) HttpRuntime.Cache.Get(CacheKey_Page(previewKey));

public static IList<IPagePlaceholderContent> GetPageContents(Guid previewKey)
=> (IList<IPagePlaceholderContent>)HttpRuntime.Cache.Get(CacheKey_Contents(previewKey));

public static RenderingReason GetRenderingReason(Guid previewKey)
=> (RenderingReason)HttpRuntime.Cache.Get(CacheKey_RenderingReason(previewKey));

public static void Remove(Guid previewKey)
{
var cache = HttpRuntime.Cache;

cache.Remove(CacheKey_Page(previewKey));
cache.Remove(CacheKey_Contents(previewKey));
cache.Remove(CacheKey_RenderingReason(previewKey));
}
}
}
19 changes: 7 additions & 12 deletions Composite/Core/WebClient/Renderings/RenderingContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -54,7 +54,7 @@ public sealed class RenderingContext: IDisposable
private static readonly List<string> _prettifyErrorUrls = new List<string>();
private static int _prettifyErrorCount;

private string _previewKey;
private Guid _previewKey;
private IDisposable _pagePerfMeasuring;
private string _cachedUrl;
private IDisposable _dataScope;
Expand Down Expand Up @@ -115,7 +115,7 @@ public bool RunResponseHandlers()
/// <exclude />
public IEnumerable<IPagePlaceholderContent> GetPagePlaceholderContents()
{
return PreviewMode ? (IEnumerable<IPagePlaceholderContent>)HttpRuntime.Cache.Get(_previewKey + "_SelectedContents")
return PreviewMode ? PagePreviewContext.GetPageContents(_previewKey)
: PageManager.GetPlaceholderContent(Page.Id, Page.VersionId);
}

Expand Down Expand Up @@ -204,15 +204,13 @@ private void InitializeFromHttpContextInternal()
_pagePerfMeasuring = Profiler.Measure("C1 Page");
}

_previewKey = request.QueryString["previewKey"];
PreviewMode = !_previewKey.IsNullOrEmpty();
PreviewMode = PagePreviewContext.TryGetPreviewKey(request, out _previewKey);

if (PreviewMode)
{
Page = (IPage)HttpRuntime.Cache.Get(_previewKey + "_SelectedPage");
Page = PagePreviewContext.GetPage(_previewKey);
C1PageRoute.PageUrlData = new PageUrlData(Page);

PageRenderer.RenderingReason = (RenderingReason) HttpRuntime.Cache.Get(_previewKey + "_RenderingReason");
PageRenderer.RenderingReason = PagePreviewContext.GetRenderingReason(_previewKey);
}
else
{
Expand Down Expand Up @@ -326,10 +324,7 @@ public void Dispose()

if (PreviewMode)
{
var cache = HttpRuntime.Cache;

cache.Remove(_previewKey + "_SelectedPage");
cache.Remove(_previewKey + "_SelectedContents");
PagePreviewContext.Remove(_previewKey);
}
}
}
Expand Down

0 comments on commit 78b472a

Please sign in to comment.