internal static async Task ManageRequest(HttpContext context, FileContentReference fileContent, string contentType = "application/javascript") { await ManageRequestHeaders(context, contentType, fileContent.ETag, fileContent.ContentLength, async() => { await context.Response.WriteAsync(fileContent.Value); }); }
private static FileContentReference GetPatchedBlazorServerFile() { if (_patchedBlazorServerFile == null) { var assembly = GetAspNetCoreComponentsServerAssembly(); var resources = assembly.GetManifestResourceNames(); var resourceName = resources.Single(str => str.EndsWith("blazor.server.js")); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) using (StreamReader reader = new StreamReader(stream)) { string js = reader.ReadToEnd(); //Patch Descriptor Regex as it make Babel crash during transform js = js.Replace("/\\W*Blazor:[^{]*(?<descriptor>.*)$/;", @"/[\0-\/:-@\[-\^`\{-\uFFFF]*Blazor:(?:(?!\{)[\s\S])*(.*)$/;"); //Transpile code to ES5 for IE11 before manual patching js = Transform(js, "blazor.server.js", "{\"plugins\":[\"proposal-class-properties\",\"proposal-object-rest-spread\"],\"presets\":[[\"env\",{\"targets\":{\"browsers\":[\"ie 11\"]}}], \"es2015\",\"es2016\",\"es2017\",\"stage-3\"], \"sourceType\": \"script\"}"); //At this point, Babel has unminified the code, and fixed IE11 issues, like 'import' method calls. //We still need to fix 'descriptor' regex evaluation code, as it was expecting a named capture group. js = Regex.Replace(js, "([a-zA-Z]+)(.groups[ ]*&&[ ]*[a-zA-Z]+.groups.descriptor)", "$1[1]"); //Minify with AjaxMin (we don't want an additional external tool with NPM or else for managing this //kind of thing here... js = Uglify.Js(js).Code; //Computing ETag. Should be computed last ! string Etag = EtagGenerator.GenerateEtagFromString(js); //Computing Build time for the Last-Modified Http Header //We should rely on the creation date of the Microsoft API //not the Blazor.Polyfill.Server one as the Microsoft.AspNetCore.Components.Server //assembly may be updated in time. We will rely on the current creation/modification date on disk DateTime buildTime = GetAssemblyCreationDate(assembly); _patchedBlazorServerFile = new FileContentReference() { Value = js, ETag = Etag, LastModified = buildTime, ContentLength = System.Text.UTF8Encoding.UTF8.GetByteCount(js).ToString(CultureInfo.InvariantCulture) }; } } return(_patchedBlazorServerFile); }
internal static async Task ManageRequest(HttpContext context, FileContentReference fileContent, string contentType = "application/javascript") { context.Response.ContentType = contentType; context.Response.Headers.Append(HeaderNames.CacheControl, "no-cache"); context.Response.Headers.Append(HeaderNames.LastModified, fileContent.LastModified.ToString("r")); context.Response.Headers.Append(HeaderNames.ETag, fileContent.ETag); //In this case we should return the entire response if (RequestHasTheNoCacheHeaderSet(context.Request) || RequestHasNoCachingFeatureSet(context.Request) || RequestHasCacheFeaturesExpired(context.Request, fileContent)) { context.Response.Headers.Append(HeaderNames.ContentLength, fileContent.ContentLength); context.Response.StatusCode = (int)HttpStatusCode.OK; await context.Response.WriteAsync(fileContent.Value); } else { context.Response.StatusCode = (int)HttpStatusCode.NotModified; } }
private static bool RequestHasCacheFeaturesExpired(HttpRequest request, FileContentReference fileContent) { string IfModifiedSince = null; string IfNoneMatch = null; DateTime IfModifiedSinceDate = default; //Must be in first check, as the library may update in the future but we can't be totally aware of the modification //date as it's related to the Microsoft library, not this one. if (request.Headers.ContainsKey(HeaderNames.IfNoneMatch)) { IfNoneMatch = request.Headers[HeaderNames.IfNoneMatch].ToString(); if (fileContent.ETag == IfNoneMatch) { return(false); } else { return(true); } } else if (request.Headers.ContainsKey(HeaderNames.IfModifiedSince)) { IfModifiedSince = request.Headers[HeaderNames.IfModifiedSince].ToString(); if (DateTime.TryParseExact(IfModifiedSince, "r", CultureInfo.InvariantCulture, DateTimeStyles.None, out IfModifiedSinceDate)) { if (IfModifiedSinceDate == fileContent.LastModified) { return(false); } else { return(true); } } } return(true); }
private static FileContentReference GetBlazorPolyfillFile(bool isIE11, bool isMinified) { if (!isIE11) { if (_fakeie11Polyfill == null) { var assembly = GetBlazorPolyfillAssembly(); var resources = assembly.GetManifestResourceNames(); var resourceName = resources.Single(str => str.EndsWith("fake.polyfill.js")); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) { using (StreamReader reader = new StreamReader(stream)) { string js = reader.ReadToEnd(); //Computing ETag. Should be computed last ! string Etag = CryptographyHelper.CreateSHA256(js); //Computing Build time for the Last-Modified Http Header DateTime buildTime = GetBlazorPolyfillServerBuildDate(); _fakeie11Polyfill = new FileContentReference() { Value = js, ETag = Etag, LastModified = buildTime, ContentLength = System.Text.UTF8Encoding.UTF8.GetByteCount(js).ToString(CultureInfo.InvariantCulture) }; } } } return(_fakeie11Polyfill); } else { if (isMinified) { if (_ie11PolyfillMin == null) { var assembly = GetBlazorPolyfillAssembly(); var resources = assembly.GetManifestResourceNames(); var resourceName = resources.Single(str => str.EndsWith("blazor.polyfill.min.js")); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) { using (StreamReader reader = new StreamReader(stream)) { string js = reader.ReadToEnd(); //Should inject es5 module override before launch js = GetOptions().GetJavascriptToInject() + js; //Computing ETag. Should be computed last ! string Etag = CryptographyHelper.CreateSHA256(js); //Computing Build time for the Last-Modified Http Header DateTime buildTime = GetBlazorPolyfillServerBuildDate(); _ie11PolyfillMin = new FileContentReference() { Value = js, ETag = Etag, LastModified = buildTime, ContentLength = System.Text.UTF8Encoding.UTF8.GetByteCount(js).ToString(CultureInfo.InvariantCulture) }; } } } return(_ie11PolyfillMin); } else { if (_ie11Polyfill == null) { var assembly = GetBlazorPolyfillAssembly(); var resources = assembly.GetManifestResourceNames(); var resourceName = resources.Single(str => str.EndsWith("blazor.polyfill.js")); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) { using (StreamReader reader = new StreamReader(stream)) { string js = reader.ReadToEnd(); //Should inject es5 module override before launch js = GetOptions().GetJavascriptToInject() + js; //Computing ETag. Should be computed last ! string Etag = CryptographyHelper.CreateSHA256(js); //Computing Build time for the Last-Modified Http Header DateTime buildTime = GetBlazorPolyfillServerBuildDate(); _ie11Polyfill = new FileContentReference() { Value = js, ETag = Etag, LastModified = buildTime, ContentLength = System.Text.UTF8Encoding.UTF8.GetByteCount(js).ToString(CultureInfo.InvariantCulture) }; } } } return(_ie11Polyfill); } } }
private static FileContentReference GetPatchedBlazorServerFile() { if (_patchedBlazorServerFile == null) { BlazorPolyfillOptions option = GetOptions(); if (option.UsePackagedBlazorServerLibrary) { //Get packaged blazor.server.js var assembly = GetBlazorPolyfillAssembly(); var resources = assembly.GetManifestResourceNames(); var resourceName = resources.Single(str => str.EndsWith("blazor.server.packaged.js")); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) { using (StreamReader reader = new StreamReader(stream)) { string js = reader.ReadToEnd(); string Etag = CryptographyHelper.CreateSHA256(js); //We should rely on ETag and not on LastModifed informations DateTime buildTime = GetAssemblyCreationDate(assembly); _patchedBlazorServerFile = new FileContentReference() { Value = js, ETag = Etag, LastModified = buildTime, ContentLength = System.Text.UTF8Encoding.UTF8.GetByteCount(js).ToString(CultureInfo.InvariantCulture) }; } } } else { var assembly = GetAspNetCoreComponentsServerAssembly(); var resources = assembly.GetManifestResourceNames(); var resourceName = resources.Single(str => str.EndsWith("blazor.server.js")); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) { using (StreamReader reader = new StreamReader(stream)) { string js = reader.ReadToEnd(); #region Patch Regex //Patch Descriptor Regex as it make Babel crash during transform js = js.Replace("/\\W*Blazor:[^{]*(?<descriptor>.*)$/;", @"/[\0-\/:-@\[-\^`\{-\uFFFF]*Blazor:(?:(?!\{)[\s\S])*(.*)$/;"); js = js.Replace("/^\\s*Blazor-Component-State:(?<state>[a-zA-Z0-9\\+\\/=]+)$/", @"/^[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]*Blazor\x2DComponent\x2DState:([\+\/-9=A-Za-z]+)$/"); js = js.Replace("/^\\s*Blazor:[^{]*(?<descriptor>.*)$/", @"/^[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]*Blazor:(?:(?!\{)[\s\S])*(.*)$/"); #endregion Patch Regex //Transpile code to ES5 for IE11 before manual patching js = BabelHelper.Transform(js, "blazor.server.js"); #region Regex named groups fix //At this point, Babel has unminified the code, and fixed IE11 issues, like 'import' method calls. //We still need to fix 'descriptor' regex evaluation code, as it was expecting a named capture group. js = Regex.Replace(js, "([_a-zA-Z0-9]+)(.groups[ ]*&&[ ]*[_a-zA-Z0-9]+.groups.descriptor)", "$1[1]"); //We still need to fix 'state' regex evaluation code, as it was expecting a named capture group. js = Regex.Replace(js, "([_a-zA-Z0-9]+)(.groups[ ]*&&[ ]*[_a-zA-Z0-9]+.groups.state)", "$1[1]"); //Here we fix invalids interopRequireWildcard(require(''.concat(n))) to _interopRequireWildcard(''.concat(n)) (works for '' or "") //Warning: " is written "" here but must be read as " from the regex logic: We are in a verbatim string js = Regex.Replace(js, @"(require\((['""]['""].concat\([a-zA-Z]+\))\))", "$2"); #endregion Regex named groups fix //Minify with AjaxMin (we don't want an additional external tool with NPM or else for managing this //kind of thing here... js = Uglify.Js(js).Code; //Computing ETag. Should be computed last ! string Etag = CryptographyHelper.CreateSHA256(js); //Computing Build time for the Last-Modified Http Header //We should rely on the creation date of the Microsoft API //not the Blazor.Polyfill.Server one as the Microsoft.AspNetCore.Components.Server //assembly may be updated in time. We will rely on the current creation/modification date on disk DateTime buildTime = GetAssemblyCreationDate(assembly); _patchedBlazorServerFile = new FileContentReference() { Value = js, ETag = Etag, LastModified = buildTime, ContentLength = System.Text.UTF8Encoding.UTF8.GetByteCount(js).ToString(CultureInfo.InvariantCulture) }; } } } } return(_patchedBlazorServerFile); }
private static FileContentReference GetIE11BlazorPolyfill(bool isIE11, bool isMinified) { if (!isIE11) { if (_fakeie11Polyfill == null) { string fakeContent = "var _fakeBlazorPolyfill = { };"; //Computing ETag. Should be computed last ! string Etag = EtagGenerator.GenerateEtagFromString(fakeContent); //Computing Build time for the Last-Modified Http Header DateTime buildTime = GetBlazorPolyfillServerBuildDate(); _fakeie11Polyfill = new FileContentReference() { Value = fakeContent, ETag = Etag, LastModified = buildTime, ContentLength = System.Text.UTF8Encoding.UTF8.GetByteCount(fakeContent).ToString(CultureInfo.InvariantCulture) }; } return(_fakeie11Polyfill); } else { if (isMinified) { if (_ie11PolyfillMin == null) { var assembly = GetBlazorPolyfillAssembly(); var resources = assembly.GetManifestResourceNames(); var resourceName = resources.Single(str => str.EndsWith("blazor.polyfill.min.js")); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) using (StreamReader reader = new StreamReader(stream)) { string js = reader.ReadToEnd(); //Computing ETag. Should be computed last ! string Etag = EtagGenerator.GenerateEtagFromString(js); //Computing Build time for the Last-Modified Http Header DateTime buildTime = GetBlazorPolyfillServerBuildDate(); _ie11PolyfillMin = new FileContentReference() { Value = js, ETag = Etag, LastModified = buildTime, ContentLength = System.Text.UTF8Encoding.UTF8.GetByteCount(js).ToString(CultureInfo.InvariantCulture) }; } } return(_ie11PolyfillMin); } else { if (_ie11Polyfill == null) { var assembly = GetBlazorPolyfillAssembly(); var resources = assembly.GetManifestResourceNames(); var resourceName = resources.Single(str => str.EndsWith("blazor.polyfill.js")); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) using (StreamReader reader = new StreamReader(stream)) { string js = reader.ReadToEnd(); //Computing ETag. Should be computed last ! string Etag = EtagGenerator.GenerateEtagFromString(js); //Computing Build time for the Last-Modified Http Header DateTime buildTime = GetBlazorPolyfillServerBuildDate(); _ie11Polyfill = new FileContentReference() { Value = js, ETag = Etag, LastModified = buildTime, ContentLength = System.Text.UTF8Encoding.UTF8.GetByteCount(js).ToString(CultureInfo.InvariantCulture) }; } } return(_ie11Polyfill); } } }