Пример #1
0
        /// <summary>
        /// Method compares the downloaded data file to the existing data
        /// file to check if the update is required. This will prevent file
        /// switching if the data file was downloaded but is not newer than
        /// the existing data file.
        /// </summary>
        /// <remarks>
        /// The following conditions must be met for the data file to be
        /// considered newer than the current master data file:
        /// 1. Current master data file does not exist.
        /// 2. If the published dates are not the same.
        /// 3. If the number of properties is not the same.
        /// </remarks>
        /// <param name="binaryFile">
        /// Current file to compare against.
        /// </param>
        /// <param name="decompressedTempFile">
        /// Path to the decompressed downloaded file.
        /// </param>
        /// <returns>The current state of the update process.</returns>
        private static AutoUpdateStatus ValidateDownloadedFile(
            FileInfo binaryFile, FileInfo decompressedTempFile)
        {
            AutoUpdateStatus status = AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS;

            if (decompressedTempFile.Exists)
            {
                // This will throw an exception if the downloaded data file
                // can't be used to get the required attributes. The exception
                // is a key part of the validation process.
                DataSetAttributes tempAttrs = new DataSetAttributes(
                    decompressedTempFile);

                // If the current binary file exists then compare the two for
                // the same published date and same properties. If either value
                // is different then the data file should be accepted. If
                // they're the same then the update is not needed.
                if (binaryFile.Exists)
                {
                    DataSetAttributes binaryAttrs = new DataSetAttributes(
                        binaryFile);
                    if (binaryAttrs.Published != tempAttrs.Published ||
                        binaryAttrs.PropertyCount != tempAttrs.PropertyCount)
                    {
                        status = AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS;
                    }
                    else
                    {
                        status = AutoUpdateStatus.AUTO_UPDATE_NOT_NEEDED;
                    }
                }
            }
            return(status);
        }
Пример #2
0
        /// <summary>
        /// Method performs the actual download by setting up and sending
        /// request and processing the response.
        /// </summary>
        /// <param name="binaryFile">
        /// File reference for the current data file.
        /// </param>
        /// <param name="client">
        /// Web client used to download the URL provided.
        /// </param>
        /// <param name="compressedTempFile">
        /// File to write compressed downloaded.
        /// </param>
        /// <param name="fullUrl">
        /// URL to use to download the data file.
        /// </param>
        /// <returns>The current status of the overall process.</returns>
        private static AutoUpdateStatus DownloadFile(
            FileInfo binaryFile,
            FileInfo compressedTempFile,
            WebClient client,
            Uri fullUrl)
        {
            AutoUpdateStatus result = AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS;

            // Set the last modified header if available from the current
            // binary data file.
            if (binaryFile.Exists)
            {
                client.Headers.Add(
                    HttpRequestHeader.LastModified,
                    binaryFile.LastWriteTimeUtc.ToString("R"));
            }

            // If the response is okay then download the file to the temporary
            // compressed data file. If not then set the response code
            // accordingly.
            try
            {
                client.DownloadFile(fullUrl, compressedTempFile.FullName);
            }
            catch (SecurityException)
            {
                result = AutoUpdateStatus.AUTO_UPDATE_HTTPS_ERR;
            }
            catch (WebException ex)
            {
                //Server response was not 200. Data download can not commence.
                switch (((HttpWebResponse)ex.Response).StatusCode)
                {
                // Note: needed because TooManyRequests is not available in
                // earlier versions of the HttpStatusCode enum.
                case ((HttpStatusCode)429):
                    result = AutoUpdateStatus.
                             AUTO_UPDATE_ERR_429_TOO_MANY_ATTEMPTS;
                    throw;

                case HttpStatusCode.NotModified:
                    result = AutoUpdateStatus.AUTO_UPDATE_NOT_NEEDED;
                    break;

                case HttpStatusCode.Forbidden:
                    result = AutoUpdateStatus.AUTO_UPDATE_ERR_403_FORBIDDEN;
                    throw;

                default:
                    result = AutoUpdateStatus.AUTO_UPDATE_HTTPS_ERR;
                    throw;
                }
            }

            EventLog.Info("Mobile detection data file successfully downloaded to '{0}'",
                          compressedTempFile.FullName);

            return(result);
        }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="message">
 /// The exception message
 /// </param>
 /// <param name="innerException">
 /// The inner exception that triggered this exception.
 /// </param>
 /// <param name="status">
 /// The <see cref="AutoUpdateStatus"/> associated with this exception.
 /// </param>
 public DataUpdateException(
     string message,
     Exception innerException,
     AutoUpdateStatus status) :
     base(message, innerException)
 {
     Status = status;
 }
Пример #4
0
        /// <summary>
        /// Updated internally from the AutoUpdateHostedService to
        /// update the status.
        /// </summary>
        /// <param name="newStatus">The new state.</param>
        /// <param name="ex">An exception can optionally be provded if the status is AutoUpdateStatus.Error</param>
        internal void Update(AutoUpdateStatus newStatus, Exception ex = null)
        {
            if (ex != null && newStatus != AutoUpdateStatus.Error)
            {
                throw new ArgumentException("An exception parameter can only be supplied if the status is AutoUpdateStatus.Error", nameof(ex));
            }

            Status    = newStatus;
            Exception = ex;
        }
Пример #5
0
        /// <summary>
        /// Verifies that the data has been downloaded correctly by comparing
        /// an MD5 hash off the downloaded data with one taken before the data
        /// was sent, which is stored in a response header.
        /// </summary>
        /// <param name="client">
        /// The Premium data download connection.
        /// </param>
        /// <param name="compressedTempFile">
        /// The path to compressed data file that has been downloaded.
        /// </param>
        /// <returns>True if the hashes match, otherwise false.</returns>
        private static AutoUpdateStatus CheckedDownloadedFileMD5(
            WebClient client, FileInfo compressedTempFile)
        {
            AutoUpdateStatus status       = AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS;
            string           serverHash   = client.ResponseHeaders["Content-MD5"];
            string           downloadHash = GetMd5Hash(compressedTempFile);

            if (serverHash == null ||
                serverHash.Equals(downloadHash) == false)
            {
                status = AutoUpdateStatus.AUTO_UPDATE_ERR_MD5_VALIDATION_FAILED;
            }
            return(status);
        }
Пример #6
0
        /// <summary>
        /// Reads a source GZip file and writes the uncompressed data to
        /// destination file.
        /// </summary>
        /// <param name="destinationPath">
        /// Path to GZip file to load from.
        /// </param>
        /// <param name="sourcePath">
        /// Path to file to write the uncompressed data to.
        /// </param>
        /// <returns>The current state of the update process.</returns>
        private static AutoUpdateStatus Decompress(
            FileInfo sourcePath, FileInfo destinationPath)
        {
            AutoUpdateStatus status = AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS;

            using (var fis = new GZipStream(
                       sourcePath.OpenRead(), CompressionMode.Decompress))
            {
                using (var fos = destinationPath.Create())
                {
                    fis.CopyTo(fos);
                }
            }
            return(status);
        }
Пример #7
0
        /// <summary>
        /// Method represents the final stage of the auto update process. The
        /// uncompressed file is swapped in place of the existing master file.
        /// </summary>
        /// <param name="binaryFile">
        /// Path to a binary data that should be set to the downloaded data.
        /// </param>
        /// <param name="client">
        /// Used to get the Last-Modified HTTP header value.
        /// </param>
        /// <param name="uncompressedTempFile">
        /// File object containing the uncompressed version of the data file
        /// downloaded from 51Degrees update server.
        /// </param>
        /// <returns>The current state of the update process.</returns>
        private static AutoUpdateStatus ActivateDownloadedFile(
            WebClient client,
            FileInfo binaryFile,
            FileInfo uncompressedTempFile)
        {
            AutoUpdateStatus status   = AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS;
            bool             backedUp = true;
            FileInfo         tempCopyofCurrentMaster = new FileInfo(
                binaryFile.FullName + ".replacing");

            try
            {
                // Keep a copy of the old data in case we need to go back to it.
                binaryFile.Refresh();
                if (binaryFile.Exists)
                {
                    try
                    {
                        File.Move(binaryFile.FullName,
                                  tempCopyofCurrentMaster.FullName);
                        backedUp = true;
                    }
                    catch
                    {
                        // The current master file can not be moved so the
                        // backup has not happened. Do not continue to try and
                        // update the data file.
                        backedUp = false;
                    }
                }

                // If the backup of the master data file exists then switch the
                // files.
                if (backedUp)
                {
                    try
                    {
                        // Copy the new file to the master file.
                        File.Move(uncompressedTempFile.FullName,
                                  binaryFile.FullName);

                        // Set the binary file's last modified date to the one
                        // provided from the web server with the download. This
                        // date will be used when checking for future updates
                        // to avoid downloading the file if there is no update.
                        binaryFile.LastWriteTimeUtc = GetLastModified(client);
                        status = AutoUpdateStatus.AUTO_UPDATE_SUCCESS;
                    }
                    catch
                    {
                        status = AutoUpdateStatus.AUTO_UPDATE_NEW_FILE_CANT_RENAME;
                    }
                }
                else
                {
                    status = AutoUpdateStatus.AUTO_UPDATE_MASTER_FILE_CANT_RENAME;
                }
            }
            catch (Exception ex)
            {
                binaryFile.Refresh();
                if (binaryFile.Exists == false &&
                    tempCopyofCurrentMaster.Exists == true)
                {
                    tempCopyofCurrentMaster.MoveTo(binaryFile.FullName);
                }
                throw ex;
            }
            finally
            {
                tempCopyofCurrentMaster.Refresh();
                if (tempCopyofCurrentMaster.Exists)
                {
                    tempCopyofCurrentMaster.Delete();
                }
            }
            return(status);
        }
Пример #8
0
        /// <summary>
        /// Downloads and updates the premium data file.
        /// </summary>
        /// <param name="licenceKeys">
        /// The licence key to use for the update request.
        /// </param>
        /// <param name="binaryFile">
        /// Location of the master data file.
        /// </param>
        /// <returns>
        /// The result of the download to enable user reporting.
        /// </returns>
        private static AutoUpdateStatus Download(
            IList <string> licenceKeys, FileInfo binaryFile)
        {
            AutoUpdateStatus result = AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS;

            // Set the three files needed to support the download, verification
            // and eventual activation.
            var compressedTempFile   = GetTempFileName(binaryFile);
            var uncompressedTempFile = GetTempFileName(binaryFile);

            try
            {
                // Acquire a lock so that only one thread can enter this
                // critical section at any given time. This is required to
                // prevent multiple threads from performing the update
                // simultaneously, i.e. if more than one thread is capable of
                // invoking AutoUpdate.
                _autoUpdateSignal.WaitOne();

                // Download the device data, decompress, check validity and
                // finally replace the existing data file if all okay.
                var client = new WebClient();
                result = DownloadFile(
                    binaryFile,
                    compressedTempFile,
                    client,
                    FullUrl(licenceKeys));

                if (result == AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS)
                {
                    result = CheckedDownloadedFileMD5(
                        client,
                        compressedTempFile);
                }

                if (result == AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS)
                {
                    result = Decompress(
                        compressedTempFile, uncompressedTempFile);
                }

                if (result == AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS)
                {
                    result = ValidateDownloadedFile(
                        binaryFile, uncompressedTempFile);
                }

                if (result == AutoUpdateStatus.AUTO_UPDATE_IN_PROGRESS)
                {
                    result = ActivateDownloadedFile(
                        client, binaryFile, uncompressedTempFile);
                }
            }
            finally
            {
                try
                {
                    if (compressedTempFile.Exists)
                    {
                        compressedTempFile.Delete();
                    }
                    if (uncompressedTempFile.Exists)
                    {
                        uncompressedTempFile.Delete();
                    }
                }
                finally
                {
                    // No matter what, release the critical section lock.
                    _autoUpdateSignal.Set();
                }
            }
            return(result);
        }
Пример #9
0
 /// <summary>
 /// Updated internally from the AutoUpdateHostedService to
 /// update the status.
 /// </summary>
 internal void Update(AutoUpdateStatus newStatus)
 {
     Status = newStatus;
 }