Skip to content

Commit

Permalink
Support for HTTP/2 Server Push
Browse files Browse the repository at this point in the history
  • Loading branch information
tpeczek committed Dec 18, 2016
1 parent 60d75bc commit 5152213
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 163 deletions.
6 changes: 0 additions & 6 deletions .nuget/NuGet.Config

This file was deleted.

Binary file removed .nuget/NuGet.exe
Binary file not shown.
133 changes: 0 additions & 133 deletions .nuget/NuGet.targets

This file was deleted.

7 changes: 0 additions & 7 deletions Lib.Web.Mvc.sln
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2012 for Web
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{BF971E7D-E0D2-4DC3-81BF-7B0E941935DD}"
ProjectSection(SolutionItems) = preProject
.nuget\NuGet.Config = .nuget\NuGet.Config
.nuget\NuGet.exe = .nuget\NuGet.exe
.nuget\NuGet.targets = .nuget\NuGet.targets
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lib.Web.Mvc", "Lib.Web.Mvc\Lib.Web.Mvc.csproj", "{1332384E-DDEF-4B55-81E8-F6F0B0C779DC}"
EndProject
Global
Expand Down
76 changes: 76 additions & 0 deletions Lib.Web.Mvc/Html/PushPromiseExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Web;
using System.Web.Mvc;

namespace Lib.Web.Mvc.Html
{
/// <summary>
/// Provides support for HTTP/2 Server Push during rendering.
/// </summary>
public static class PushPromiseExtensions
{
#region Constants
private const string _linkElement = "link";
private const string _scriptElement = "script";

private const string _hrefAttribute = "href";
private const string _relationAttribute = "rel";
private const string _sourceAttribute = "src";
private const string _typeAttribute = "type";
#endregion

#region Methods
/// <summary>
/// Provides HTTP/2 Server Push support for link elements.
/// </summary>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="contentPath">The virtual path of resource.</param>
/// <param name="relation">The relation (default is stylesheet).</param>
/// <returns></returns>
public static IHtmlString PushPromiseLink(this HtmlHelper htmlHelper, string contentPath, string relation = "stylesheet")
{
PushPromise(htmlHelper.ViewContext.HttpContext, contentPath);

UrlHelper urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);

TagBuilder linkTagBuilder = new TagBuilder(_linkElement);
linkTagBuilder.Attributes.Add(_relationAttribute, relation);
linkTagBuilder.Attributes.Add(_hrefAttribute, urlHelper.Content(contentPath));

return new HtmlString(linkTagBuilder.ToString());
}

/// <summary>
/// Provides HTTP/2 Server Push support for script elements.
/// </summary>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="contentPath">The virtual path of resource.</param>
/// <param name="type">The type.</param>
/// <returns></returns>
public static IHtmlString PushPromiseScript(this HtmlHelper htmlHelper, string contentPath, string type = "")
{
PushPromise(htmlHelper.ViewContext.HttpContext, contentPath);

UrlHelper urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);

TagBuilder scriptTagBuilder = new TagBuilder(_scriptElement);
scriptTagBuilder.Attributes.Add(_sourceAttribute, urlHelper.Content(contentPath));

if (!String.IsNullOrWhiteSpace(type))
{
scriptTagBuilder.Attributes.Add(_typeAttribute, type);
}

return new HtmlString(scriptTagBuilder.ToString());
}

private static void PushPromise(HttpContextBase httpContext, string contentPath)
{
if (httpContext.Request.IsSecureConnection)
{
httpContext.Response.PushPromise(contentPath);
}
}
#endregion
}
}
30 changes: 16 additions & 14 deletions Lib.Web.Mvc/Lib.Web.Mvc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Lib.Web.Mvc</RootNamespace>
<AssemblyName>Lib.Web.Mvc</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\jqGrid Helper Examples\</SolutionDir>
Expand Down Expand Up @@ -50,6 +50,7 @@
<Compile Include="ContentSecurityPolicyAttribute.cs" />
<Compile Include="Html\ContentSecurityPolicyExtensions.cs" />
<Compile Include="Html\RenderXmlExtensions.cs" />
<Compile Include="Html\PushPromiseExtensions.cs" />
<Compile Include="JQuery\JqGrid\Constants\JqGridColumnPredefinedFormatters.cs" />
<Compile Include="JQuery\JqGrid\Constants\JqGridFilterToolbarDefaults.cs" />
<Compile Include="JQuery\JqGrid\Constants\JqGridNavigatorDefaults.cs" />
Expand Down Expand Up @@ -149,6 +150,8 @@
<Compile Include="NoCacheAttribute.cs" />
<Compile Include="NoAjaxRequestAttribute.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PushPromiseAttribute.cs" />
<Compile Include="PushPromiseTable.cs" />
<Compile Include="RangeFileContentResult.cs" />
<Compile Include="RangeFilePathResult.cs" />
<Compile Include="RangeFileResult.cs" />
Expand All @@ -167,28 +170,28 @@
<Reference Include="System.Data.Linq" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Helpers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\TPeczek.Blog.ContentSecurityPolicy\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll</HintPath>
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\Demo.AspNet.Mvc.Http2\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Web.Mvc, Version=4.0.0.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\TPeczek.Blog.ContentSecurityPolicy\packages\Microsoft.AspNet.Mvc.4.0.40804.0\lib\net40\System.Web.Mvc.dll</HintPath>
<Reference Include="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\Demo.AspNet.Mvc.Http2\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Web.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\TPeczek.Blog.ContentSecurityPolicy\packages\Microsoft.AspNet.Razor.2.0.20710.0\lib\net40\System.Web.Razor.dll</HintPath>
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\Demo.AspNet.Mvc.Http2\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Web.WebPages, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\TPeczek.Blog.ContentSecurityPolicy\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll</HintPath>
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\Demo.AspNet.Mvc.Http2\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Web.WebPages.Deployment, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\TPeczek.Blog.ContentSecurityPolicy\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll</HintPath>
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\Demo.AspNet.Mvc.Http2\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\TPeczek.Blog.ContentSecurityPolicy\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll</HintPath>
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\Projekty\Demo.AspNet.Mvc.Http2\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.XML" />
Expand All @@ -197,7 +200,6 @@
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
Expand Down
64 changes: 64 additions & 0 deletions Lib.Web.Mvc/PushPromiseAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Web.Mvc;

namespace Lib.Web.Mvc
{
/// <summary>
/// Action filter providing server push promise support
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class PushPromiseAttribute : FilterAttribute, IActionFilter
{
#region Fields
private PushPromiseTable _pushPromiseTable;
#endregion

#region Constructor
/// <summary>
/// Initializes new instance of PushPromiseAttribute
/// </summary>
/// <param name="pushPromiseTable">The push promises table.</param>
public PushPromiseAttribute(PushPromiseTable pushPromiseTable)
{
if (pushPromiseTable == null)
{
throw new ArgumentNullException(nameof(pushPromiseTable));
}

_pushPromiseTable = pushPromiseTable;
}
#endregion

#region IActionFilter Members
/// <summary>
/// Called after the action method executes.
/// </summary>
/// <param name="filterContext"></param>
public void OnActionExecuted(ActionExecutedContext filterContext)
{ }

/// <summary>
/// Called before an action method executes.
/// </summary>
/// <param name="filterContext"></param>
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException(nameof(filterContext));
}

// HTTP/2 is supported only over HTTPS
if (filterContext.HttpContext.Request.IsSecureConnection)
{
IEnumerable<string> pushPromiseContentPaths = _pushPromiseTable.GetPushPromiseContentPaths(filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor.ActionName);
foreach (string pushPromiseContentPath in pushPromiseContentPaths)
{
filterContext.HttpContext.Response.PushPromise(pushPromiseContentPath);
}
}
}
#endregion
}
}
Loading

0 comments on commit 5152213

Please sign in to comment.