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); } }
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. }