diff --git a/platform/http_request.cpp b/platform/http_request.cpp index 5cbc6158e7..2b4803abd0 100644 --- a/platform/http_request.cpp +++ b/platform/http_request.cpp @@ -212,17 +212,7 @@ class FileHttpRequest : public HttpRequest, public IHttpThreadCallback if (m_status != EInProgress) { - try - { - m_writer.reset(); - } - catch (Writer::Exception const & ex) - { - LOG(LWARNING, ("Can't close file correctly. There is not enough space, possibly.")); - - ASSERT_EQUAL ( m_status, EFailed, () ); - m_status = EFailed; - } + CloseWriter(); // clean up resume file with chunks range on success if (m_status == ECompleted) @@ -242,6 +232,20 @@ class FileHttpRequest : public HttpRequest, public IHttpThreadCallback } } + void CloseWriter() + { + try + { + m_writer.reset(); + } + catch (Writer::Exception const & ex) + { + LOG(LWARNING, ("Can't close file correctly. There is not enough space, possibly.")); + + m_status = EFailed; + } + } + public: FileHttpRequest(vector const & urls, string const & filePath, int64_t fileSize, CallbackT const & onFinish, CallbackT const & onProgress, @@ -251,13 +255,29 @@ public: { ASSERT ( !urls.empty(), () ); - // Open file here. Avoid throwing exceptions from constructor's initialization list. - m_writer.reset(new FileWriter(filePath + DOWNLOADING_FILE_EXTENSION, FileWriter::OP_WRITE_EXISTING)); - + // Load resume downloading information. m_progress.first = m_strategy.LoadOrInitChunks(m_filePath + RESUME_FILE_EXTENSION, fileSize, chunkSize); m_progress.second = fileSize; + FileWriter::Op openMode = FileWriter::OP_WRITE_TRUNCATE; + if (m_progress.first != 0) + { + // Check that resume information is correct with existing file. + uint64_t size; + if (my::GetFileSize(filePath + DOWNLOADING_FILE_EXTENSION, size) && size == fileSize) + openMode = FileWriter::OP_WRITE_EXISTING; + else + m_strategy.InitChunks(fileSize, chunkSize); + } + + // Create file and reserve needed size. + scoped_ptr writer(new FileWriter(filePath + DOWNLOADING_FILE_EXTENSION, openMode)); + writer->Reserve(fileSize); + + // Assign here, because previous functions can throw an exception. + m_writer.swap(writer); + #ifdef OMIM_OS_IPHONE m_writer->Flush(); DisableBackupForFile(filePath + DOWNLOADING_FILE_EXTENSION); @@ -274,12 +294,12 @@ public: if (m_status == EInProgress) { // means that client canceled download process, so delete all temporary files - m_writer.reset(); + CloseWriter(); if (m_doCleanProgressFiles) { - my::DeleteFileX(m_filePath + DOWNLOADING_FILE_EXTENSION); - my::DeleteFileX(m_filePath + RESUME_FILE_EXTENSION); + (void)my::DeleteFileX(m_filePath + DOWNLOADING_FILE_EXTENSION); + (void)my::DeleteFileX(m_filePath + RESUME_FILE_EXTENSION); } } } @@ -328,29 +348,26 @@ namespace }; } -HttpRequest * HttpRequest::GetFile(vector const & urls, string const & filePath, int64_t fileSize, +HttpRequest * HttpRequest::GetFile(vector const & urls, + string const & filePath, int64_t fileSize, CallbackT const & onFinish, CallbackT const & onProgress, - int64_t chunkSize, bool doCleanProgressFiles) + int64_t chunkSize, bool doCleanOnCancel) { - FileHttpRequest * p = 0; try { - p = new FileHttpRequest(urls, filePath, fileSize, onFinish, onProgress, chunkSize, doCleanProgressFiles); + return new FileHttpRequest(urls, filePath, fileSize, onFinish, onProgress, chunkSize, doCleanOnCancel); } catch (FileWriter::Exception const & e) { - // Can't create file for writing. + // Can't create or open file for writing. LOG(LERROR, ("Can't create FileHttpRequest for", filePath, e.what())); - delete p; - p = 0; - // Mark the end of download with error. ErrorHttpRequest error(filePath); onFinish(error); - } - return p; + return 0; + } } } // namespace downloader diff --git a/platform/http_request.hpp b/platform/http_request.hpp index 8f03e033cc..af3e055b86 100644 --- a/platform/http_request.hpp +++ b/platform/http_request.hpp @@ -22,7 +22,7 @@ public: /// , total can be -1 if size is unknown typedef pair ProgressT; - typedef function CallbackT; + typedef function CallbackT; protected: StatusT m_status; @@ -44,16 +44,20 @@ public: static HttpRequest * Get(string const & url, CallbackT const & onFinish, CallbackT const & onProgress = CallbackT()); + /// Content-type for request is always "application/json" static HttpRequest * PostJson(string const & url, string const & postData, CallbackT const & onFinish, CallbackT const & onProgress = CallbackT()); - static HttpRequest * GetFile(vector const & urls, string const & filePath, - int64_t projectedFileSize, + + /// Download file to filePath. + /// @param[in] fileSize Correct file size (needed for resuming and reserving). + static HttpRequest * GetFile(vector const & urls, + string const & filePath, int64_t fileSize, CallbackT const & onFinish, CallbackT const & onProgress = CallbackT(), int64_t chunkSize = 512 * 1024, - bool doCleanProgressFiles = true); + bool doCleanOnCancel = true); }; } // namespace downloader