diff --git a/iphone/Maps/Platform/IPhoneDownload.h b/iphone/Maps/Platform/IPhoneDownload.h index bac2714e68..c77b970162 100644 --- a/iphone/Maps/Platform/IPhoneDownload.h +++ b/iphone/Maps/Platform/IPhoneDownload.h @@ -16,6 +16,8 @@ TDownloadFinishedFunction m_finishObserver; TDownloadProgressFunction m_progressObserver; + + NSInteger m_retryCounter; } - (void) dealloc; diff --git a/iphone/Maps/Platform/IPhoneDownload.mm b/iphone/Maps/Platform/IPhoneDownload.mm index b7d4a3103c..c0f6d2d9e3 100644 --- a/iphone/Maps/Platform/IPhoneDownload.mm +++ b/iphone/Maps/Platform/IPhoneDownload.mm @@ -3,6 +3,7 @@ #include "../../platform/download_manager.hpp" #define TIMEOUT_IN_SECONDS 15.0 +#define MAX_AUTOMATIC_RETRIES 3 @implementation IPhoneDownload @@ -37,6 +38,22 @@ [super dealloc]; } +- (NSMutableURLRequest *) CreateRequest +{ + // Create the request. + NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString: [NSString stringWithUTF8String:m_url.c_str()]] + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:TIMEOUT_IN_SECONDS]; + long long fileSize = ftello(m_file); + if (fileSize > 0) + { + NSLog(@"Resuming download for file %s from position %qi", m_requestedFileName.c_str(), fileSize); + NSString * val = [[NSString alloc] initWithFormat: @"bytes=%qi-", fileSize]; + [request addValue:val forHTTPHeaderField:@"Range"]; + [val release]; + } + return request; +} + - (BOOL) StartDownloadWithUrl: (char const *)originalUrl andFile: (char const *)file andFinishFunc: (TDownloadFinishedFunction &)finishFunc andProgressFunc: (TDownloadProgressFunction &)progressFunc andUseResume: (BOOL)resume @@ -44,6 +61,8 @@ m_finishObserver = finishFunc; m_progressObserver = progressFunc; + m_retryCounter = 0; + // try to create file first std::string tmpFile = file; tmpFile += DOWNLOADING_FILE_EXTENSION; @@ -60,19 +79,9 @@ m_requestedFileName = file; m_url = originalUrl; - // Create the request. - NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString: [NSString stringWithUTF8String:m_url.c_str()]] - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:TIMEOUT_IN_SECONDS]; - long long fileSize = ftello(m_file); - if (resume && fileSize > 0) - { - NSString * val = [[NSString alloc] initWithFormat: @"bytes=%qi-", fileSize]; - [request addValue:val forHTTPHeaderField:@"Range"]; - [val release]; - } // create the connection with the request and start loading the data - m_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; -// [request release]; + m_connection = [[NSURLConnection alloc] initWithRequest:[self CreateRequest] delegate:self]; + if (m_connection == 0) { NSLog(@"Can't create connection for url %s", originalUrl); @@ -131,7 +140,25 @@ - (void) connection: (NSURLConnection *)connection didFailWithError: (NSError *)error { // inform the user - NSLog(@"Connection failed! Error - %@ %s", [error localizedDescription], m_url.c_str()); + NSLog(@"Connection failed for url %s\n%@", m_url.c_str(), [error localizedDescription]); + + // retry connection if it's network-specific error + if ([error code] < 0 && ++m_retryCounter <= MAX_AUTOMATIC_RETRIES) + { + [m_connection release]; + // create the connection with the request and start loading the data + m_connection = [[NSURLConnection alloc] initWithRequest:[self CreateRequest] delegate:self]; + + if (m_connection) + { + NSLog(@"Retrying %d time", m_retryCounter); + return; // successfully restarted connection + } + + NSLog(@"Can't retry connection"); + // notify observer about error and exit after this if-block + } + if (m_finishObserver) m_finishObserver(m_url.c_str(), false); // and selfdestruct... diff --git a/platform/qt_download.cpp b/platform/qt_download.cpp index 4fb22be926..6cdabc011b 100644 --- a/platform/qt_download.cpp +++ b/platform/qt_download.cpp @@ -4,11 +4,15 @@ #include "../base/logging.hpp" #include "../base/assert.hpp" +// How many times we try to automatically reconnect in the case of network errors +#define MAX_AUTOMATIC_RETRIES 2 + QtDownload::QtDownload(QtDownloadManager & manager, char const * url, char const * fileName, TDownloadFinishedFunction & finish, TDownloadProgressFunction & progress, bool useResume) : QObject(&manager), m_currentUrl(url), m_reply(0), m_file(0), - m_httpRequestAborted(false), m_finish(finish), m_progress(progress) + m_httpRequestAborted(false), m_finish(finish), m_progress(progress), + m_retryCounter(0) { // use temporary file for download QString tmpFileName(fileName); @@ -91,9 +95,18 @@ void QtDownload::OnHttpFinished() m_file->close(); QVariant redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - if (m_reply->error()) + QNetworkReply::NetworkError netError = m_reply->error(); + if (netError) { - m_file->remove(); + if (netError <= QNetworkReply::UnknownNetworkError && ++m_retryCounter <= MAX_AUTOMATIC_RETRIES) + { // try one more time + m_reply->deleteLater(); + StartRequest(); + return; + } + // do not delete file if we can resume it's downloading later + if (m_file->pos() == 0) + m_file->remove(); delete m_file; m_file = 0; @@ -128,6 +141,7 @@ void QtDownload::OnHttpFinished() QFile::remove(originalFileName); if (!m_file->rename(originalFileName)) { // sh*t... file is locked and can't be removed + m_file->remove(); // report error to GUI LOG(LERROR, ("File exists and can't be replaced by downloaded one:", qPrintable(originalFileName))); resultForGui = false; diff --git a/platform/qt_download.hpp b/platform/qt_download.hpp index 40e4ba28ca..5d44ce7926 100644 --- a/platform/qt_download.hpp +++ b/platform/qt_download.hpp @@ -17,6 +17,7 @@ private: bool m_httpRequestAborted; TDownloadFinishedFunction m_finish; TDownloadProgressFunction m_progress; + int m_retryCounter; QtDownload(QtDownloadManager & manager, char const * url, char const * fileName, TDownloadFinishedFunction & finish, TDownloadProgressFunction & progress,