/// <summary> /// Sends the request result package to the client /// </summary> /// <returns>The size of the package sent.</returns> public long SendResponsePackage() { // build the package index _package.BuildPackageIndex(PackageFileName, Proxy.ProxyCacheManager); Logger.Debug("sending results package: " + (_package.IndexSize + _package.ContentSize) + " bytes at " + _proxy.MAXIMUM_DOWNLINK_BANDWIDTH + " bytes per second."); // Add response headers RCSpecificResponseHeaders headers = new RCSpecificResponseHeaders(_package.IndexSize, _package.ContentSize); AddRCSpecificResponseHeaders(headers); // stream out the pages (w/compression) LinkedList<string> fileNames = new LinkedList<string>(); fileNames.AddLast(PackageFileName); foreach (RCRequest rcRequest in _package.RCRequests) { fileNames.AddLast(rcRequest.CacheFileName); } MemoryStream ms = GZipWrapper.GZipCompress(fileNames); return StreamToClient(ms); }
/// <summary> /// Unpacks the package contents and indexes them. Throws an Exception if anything goes wrong. /// </summary> /// <param name="requestHandler">Calling handler for this method.</param> /// <param name="rcheaders">The rc specific headers.</param> /// <returns>Total unpacked content size.</returns> public static long Unpack(LocalRequestHandler requestHandler, RCSpecificResponseHeaders rcheaders) { long packageIndexSize = rcheaders.RCPackageIndexSize; long packageContentSize = rcheaders.RCPackageContentSize; if (packageIndexSize == 0 || packageContentSize == 0) { // This is an internal error that should not happen! throw new Exception("problem unpacking: package index or content size is 0."); } string packageFileName = requestHandler.PackageFileName; string unpackedPackageFileName = packageFileName.Replace(".gzip", ""); GZipWrapper.GZipDecompress(packageFileName, unpackedPackageFileName, packageIndexSize + packageContentSize); FileStream packageFs = new FileStream(unpackedPackageFileName, FileMode.Open); // read the package index Byte[] packageIndexBuffer = new Byte[packageIndexSize]; int bytesOfIndexRead = 0; while (bytesOfIndexRead != packageIndexSize) { int read = packageFs.Read(packageIndexBuffer, bytesOfIndexRead, (int)(packageIndexSize - bytesOfIndexRead)); if(read == 0) { // This should not happen throw new Exception("problem unpacking: could not read index."); } bytesOfIndexRead += read; } // split the big package file into pieces string[] stringSeparator = new string[] { "\r\n" }; System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); string package = enc.GetString(packageIndexBuffer); string[] packageContentArr = package.Split(stringSeparator, StringSplitOptions.RemoveEmptyEntries); long unpackedBytes = 0; HashSet<GlobalCacheItemToAdd> itemsToAdd = new HashSet<GlobalCacheItemToAdd>(); try { for (int i = 0; i < packageContentArr.Length; i += 2) { // Index format is 2 lines: // <statusCode> <fileSize> <filename> (filename is last, as it can have spaces) // <headers> (JSON) string[] firstLineArray = packageContentArr[i].Split(new string[] { " " }, 3, StringSplitOptions.None); if (firstLineArray.Length != 3) { throw new Exception("unparseable entry: " + packageContentArr[i]); } short statusCode; long fileSize; try { statusCode = Int16.Parse(firstLineArray[0]); fileSize = Int64.Parse(firstLineArray[1]); } catch (Exception) { throw new Exception("unparseable entry: " + packageContentArr[i]); } string fileName = firstLineArray[2]; string headersJson = packageContentArr[i + 1]; NameValueCollection headers = JsonConvert.DeserializeObject<NameValueCollection>(headersJson, new NameValueCollectionConverter()); if (requestHandler.Proxy.ProxyCacheManager.CreateOrUpdateFileAndWrite(fileName, fileSize, packageFs)) { unpackedBytes += fileSize; // We index only if (i==0), which means only the first file of the package. This is the main // page that has been requested. Embedded pages won't be indexed. GlobalCacheItemToAdd newItem = new GlobalCacheItemToAdd(fileName, headers, statusCode, i == 0); itemsToAdd.Add(newItem); } } } finally { if (packageFs != null) { packageFs.Close(); } // Add all Database entries if (!requestHandler.Proxy.ProxyCacheManager.AddCacheItemsForExistingFiles(itemsToAdd)) { // Adding to the DB failed throw new Exception("Adding an item to the database failed."); } } return unpackedBytes; }