/// <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);
        }
Exemple #2
0
        /// <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;
        }