示例#1
0
        public string GetLocalSrc(bool useDevVersion)
        {
            string localSrc = (!useDevVersion || this.minonly || !Minifier.IsMinName(this.fallback_src)) ? this.fallback_src : Minifier.GetNonMinName(this.fallback_src);

            if (this.version != null)
            {
                // version For local files. Equiv to "asp-append-version"
                localSrc += "?v=" + this.version;
            }
            return(localSrc);
        }
示例#2
0
        public async Task <CdnRet> SyncElement(string outDir)
        {
            // Test a <a>, <link> or <script> element. Pull it from CDN if it doesn't exist locally.
            // RETURN: CdnRet : 0 = no update required, 1 = pulled file. -1=error

            try
            {
                string dstPath = GetPhysPathFromWeb(outDir, this.fallback_src);     // Make a real (app relative) physical path for destination.

                CdnRet ret = await SyncFile(dstPath);

                if (ret <= CdnRet.Error)
                {
                    return(ret);
                }

                // Does it have a .map file?
                string mapPath;
                if (this.map != null)
                {
                    mapPath = UrlUtil.ReplaceFile(dstPath, this.map); // replace name.
                    if (ret == CdnRet.Updated || !File.Exists(mapPath))
                    {
                        var dlMap = new HttpDownloader(UrlUtil.ReplaceFile(this.CdnPath1, this.map), mapPath);
                        await dlMap.DownloadFileAsync();
                    }
                }

                // Pull the non-minified (Dev) version as well. if it has one.
                if (this.CdnPath1 != null && !this.minonly && Minifier.IsMinName(this.CdnPath1))  // it is minified?
                {
                    string devName = Minifier.GetNonMinName(dstPath);
                    if (ret == CdnRet.Updated || !File.Exists(devName))
                    {
                        var dlDev = new HttpDownloader(Minifier.GetNonMinName(this.CdnPath1), devName);
                        await dlDev.DownloadFileAsync();
                    }
                }

                return(ret);
            }
            catch
            {
                // This is only run at startup and failure is very bad! Should we allow the server to start at all ?
                return(CdnRet.Error);
            }
        }
示例#3
0
        public CdnResource(string _name, string _tagname, string outDir)
        {
            // create an element on the fly. Assume _name is a local minified file. NOT CDN.
            // <IncludeRef name="/js/grid_common.min.js" tagname="script" /> // use minified name to indicate it has one.

            ValidState.ThrowIfWhiteSpace(_name, "CdnResource name");
            name         = _name;
            fallback_src = name;

            if (_tagname == null)
            {
                // derive from the file extension.
                if (_name.EndsWith(Minifier.kExtJs))
                {
                    TagName = CdnTagName.script;
                }
                else if (_name.EndsWith(Minifier.kExtCss))
                {
                    TagName = CdnTagName.link;
                }
                else
                {
                    TagName = CdnTagName.a;
                }
            }
            else
            {
                TagName = EnumUtil.ParseEnum <CdnTagName>(_tagname);
            }

            // Does it have a minified file? assume _name is the minified version.
            string path1   = GetPhysPathFromWeb(outDir, name);
            string name2   = Minifier.GetNonMinName(name);
            string path2   = GetPhysPathFromWeb(outDir, name2);
            bool   exists1 = File.Exists(path1);
            bool   exists2 = File.Exists(path2);

            if (exists1)
            {
                minonly = !exists2; // min exists. but does non-min ?
            }
            else if (exists2)
            {
                name    = name2; // only non-min version exists.
                path1   = path2;
                minonly = true;
            }
            else
            {
                // neither exists. this is bad.
                TagName = CdnTagName.ERROR;
                minonly = false;
                return;
            }

            // cache breaking version For local files. Equiv to "asp-append-version" (would use SHA256)

            var hasher = new HashUtil(HashUtil.GetMD5());       // GetSHA256()

            byte[] hashCode2 = hasher.GetHashFile(path1);
            Debug.Assert(hashCode2 != null);
            version = Convert.ToBase64String(hashCode2);
        }
示例#4
0
        public async Task <CdnRet> SyncFile(string dstPath)
        {
            // Get a file from CDN if i don't already have it and check its integrity (if supplied)
            // can throw.

            byte[]   hashCode1 = null;
            HashUtil hasher    = null;

            var fi = new FileInfo(dstPath);

            if (integrity == null)
            {
                // integrity doesn't exist so just check that the file exists locally.
                if (fi.Exists && fi.Length > 0)
                {
                    await UpdateIntegrity(dstPath); // suggest that we manually update integrity.

                    return(CdnRet.Valid);           // it exists. good enough since we don't have integrity attribute.
                }

                // It doesn't exist locally. pull a local copy from CDN. No big deal.
            }
            else
            {
                // test local file integrity hash e.g. "sha256-", "sha384-"
                int i = integrity.IndexOf(kIntegritySep);
                if (i <= 0)     // badly formed integrity ?? Fail ?
                {
                    // This is bad !! i cant really fix this. fix it manually.
                    LoggerUtil.DebugException($"Bad CDN integrity format '{integrity}'", null);
                    return(CdnRet.Error);
                }

                hashCode1 = Convert.FromBase64String(integrity.Substring(i + 1));
                hasher    = new HashUtil(HashUtil.FindHasherByName(integrity));
                if (fi.Exists)
                {
                    // Does current file match integrity?
                    byte[] hashCode2 = await hasher.GetHashFileAsync(dstPath);

                    Debug.Assert(hashCode2 != null);

                    // string debugHash2 = Convert.ToBase64String(hashCode2);
                    if (ByteUtil.CompareBytes(hashCode1, hashCode2) == 0)     // integrity match is good. Skip this.
                    {
                        return(CdnRet.Valid);
                    }

                    // local file DOES NOT MATCH integrity!!
                    // This really should never happen! Pull another file from the CDN and hope it matches.
                }
            }

            if (this.CdnPath1 == null)
            {
                // this file has no CDN. So i can't do anything!

                if (Minifier.IsMinName(dstPath) && await Minifier.CreateMinified(Minifier.GetNonMinName(dstPath), dstPath))
                {
                    // Local only lacked a minified version. so i made one.
                    return(CdnRet.Updated);
                }

                LoggerUtil.DebugException($"No File ({integrity}) and No CDN path for '{name}'", null);
                return(CdnRet.Error);
            }

            // Pull/Get the file from CDN.
            LoggerUtil.DebugEntry($"Get '{this.CdnPath1}'");
            var dl = new HttpDownloader(this.CdnPath1, dstPath);

            // CDN can get "OperationCanceledException: The operation was canceled."
            await dl.DownloadFileAsync(true);  // Assume directory is created on demand.

            if (integrity == null)
            {
                // destination file should exist now. Does it?
                var fi2 = new FileInfo(dstPath);
                if (!fi2.Exists || fi2.Length <= 0)
                {
                    LoggerUtil.DebugException("CDN file size 0 for " + dstPath, null);
                    return(CdnRet.Error);
                }

                await UpdateIntegrity(dstPath);
            }
            else
            {
                // Now (re)test integrity for the file i just got!
                hasher.Init();
                byte[] hashCode2 = await hasher.GetHashFileAsync(dstPath);

                if (ByteUtil.CompareBytes(hashCode1, hashCode2) != 0)     // MUST match.
                {
                    // This is BAD. It should never happen!
                    string debugHash2 = Convert.ToBase64String(hashCode2);
                    LoggerUtil.DebugException($"CDN integrity hash does not match for '{dstPath}'. should be integrity='{string.Concat(kIntegrityAlgDef, kIntegritySep, debugHash2)}'", null);
                    return(CdnRet.Error);
                }
            }

            return(CdnRet.Updated);       // got it.
        }