Commit message: None
CVE: CVE-2013-0892
Vulnerability description: Multiple unspecified vulnerabilities in the IPC layer in Google Chrome before 25.0.1364.97 on Windows and Linux, and before 25.0.1364.99 on Mac OS X, allow remote attackers to cause a denial of service or possibly have other impact via unknown vectors.

Project: Chrome

bool CanSaveAsComplete(const std::string& contents_mime_type) {
  return contents_mime_type == "text/html" ||
         contents_mime_type == "application/xhtml+xml";
}

Project: Chrome

void SavePackage::Cancel(bool user_action) {
  if (!canceled()) {
    if (user_action)
      user_canceled_ = true;
    else
      disk_error_occurred_ = true;
    Stop();
  }
  RecordSavePackageEvent(SAVE_PACKAGE_CANCELLED);
}

Project: Chrome

void SavePackage::CheckFinish() {
  if (in_process_count() || finished_)
    return;

  FilePath dir = (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML &&
                  saved_success_items_.size() > 1) ?
                  saved_main_directory_path_ : FilePath();

  FinalNameList final_names;
  for (SavedItemMap::iterator it = saved_success_items_.begin();
      it != saved_success_items_.end(); ++it)
    final_names.push_back(std::make_pair(it->first,
                                         it->second->full_path()));

  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&SaveFileManager::RenameAllFiles,
                 file_manager_,
                 final_names,
                 dir,
                 web_contents()->GetRenderProcessHost()->GetID(),
                 web_contents()->GetRenderViewHost()->GetRoutingID(),
                 id()));
}

Project: Chrome

void SavePackage::ContinueGetSaveInfo(const FilePath& suggested_path,
                                      bool can_save_as_complete) {

  if (!web_contents() || !download_manager_->GetDelegate())
    return;

  FilePath::StringType default_extension;
  if (can_save_as_complete)
    default_extension = kDefaultHtmlExtension;

  download_manager_->GetDelegate()->ChooseSavePath(
      web_contents(),
      suggested_path,
      default_extension,
      can_save_as_complete,
      base::Bind(&SavePackage::OnPathPicked, AsWeakPtr()));
}

Project: Chrome

void SavePackage::CreateDirectoryOnFileThread(
    const FilePath& website_save_dir,
    const FilePath& download_save_dir,
    bool skip_dir_check,
    const std::string& mime_type,
    const std::string& accept_langs) {
  FilePath save_dir;
  if (!skip_dir_check && !file_util::DirectoryExists(website_save_dir)) {
    if (!file_util::DirectoryExists(download_save_dir)) {
      bool res = file_util::CreateDirectory(download_save_dir);
      DCHECK(res);
    }
    save_dir = download_save_dir;
  } else {
    save_dir = website_save_dir;
  }

  bool can_save_as_complete = CanSaveAsComplete(mime_type);
  FilePath suggested_filename = GetSuggestedNameForSaveAs(
      can_save_as_complete, mime_type, accept_langs);
  FilePath::StringType pure_file_name =
      suggested_filename.RemoveExtension().BaseName().value();
  FilePath::StringType file_name_ext = suggested_filename.Extension();

  uint32 max_path = GetMaxPathLengthForDirectory(save_dir);

  if (GetSafePureFileName(save_dir, file_name_ext, max_path, &pure_file_name)) {
    save_dir = save_dir.Append(pure_file_name + file_name_ext);
  } else {
    save_dir = save_dir.Append(suggested_filename);
  }

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&SavePackage::ContinueGetSaveInfo, this, save_dir,
                 can_save_as_complete));
}

Project: Chrome

int64 SavePackage::CurrentSpeed() const {
  base::TimeDelta diff = base::TimeTicks::Now() - start_tick_;
  int64 diff_ms = diff.InMilliseconds();
  return diff_ms == 0 ? 0 : completed_count() * 1000 / diff_ms;
}

Project: Chrome

void SavePackage::DoSavingProcess() {
  if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) {
    SaveItem* save_item = NULL;
    if (waiting_item_queue_.size()) {
      DCHECK(wait_state_ == NET_FILES);
      save_item = waiting_item_queue_.front();
      if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) {
        SaveNextFile(false);
      } else if (!in_process_count()) {
        wait_state_ = HTML_DATA;
        SaveNextFile(true);
      }
    } else if (in_process_count()) {
      DCHECK(wait_state_ == HTML_DATA);
    }
  } else {
    DCHECK(wait_state_ == NET_FILES);
    DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) ||
           (save_type_ == SAVE_PAGE_TYPE_AS_MHTML));
    if (waiting_item_queue_.size()) {
      DCHECK(all_save_items_count_ == waiting_item_queue_.size());
      SaveNextFile(false);
    }
  }
}

Project: Chrome

FilePath SavePackage::EnsureHtmlExtension(const FilePath& name) {
  FilePath::StringType ext = name.Extension();
  if (!ext.empty())
    ext.erase(ext.begin());  // Erase preceding '.'.
  std::string mime_type;
  if (!net::GetMimeTypeFromExtension(ext, &mime_type) ||
      !CanSaveAsComplete(mime_type)) {
    return FilePath(name.value() + FILE_PATH_LITERAL(".") +
                    kDefaultHtmlExtension);
  }
  return name;
}

Project: Chrome

FilePath SavePackage::EnsureMimeExtension(const FilePath& name,
    const std::string& contents_mime_type) {
  FilePath::StringType ext = name.Extension().length() ?
      name.Extension().substr(1) : name.Extension();
  FilePath::StringType suggested_extension =
      ExtensionForMimeType(contents_mime_type);
  std::string mime_type;
  if (!suggested_extension.empty() &&
      !net::GetMimeTypeFromExtension(ext, &mime_type)) {
    return FilePath(name.value() + FILE_PATH_LITERAL(".") +
                    suggested_extension);
  }
  return name;
}

Project: Chrome

const FilePath::CharType* SavePackage::ExtensionForMimeType(
    const std::string& contents_mime_type) {
  static const struct {
    const FilePath::CharType *mime_type;
    const FilePath::CharType *suggested_extension;
  } extensions[] = {
    { FILE_PATH_LITERAL("text/html"), kDefaultHtmlExtension },
    { FILE_PATH_LITERAL("text/xml"), FILE_PATH_LITERAL("xml") },
    { FILE_PATH_LITERAL("application/xhtml+xml"), FILE_PATH_LITERAL("xhtml") },
    { FILE_PATH_LITERAL("text/plain"), FILE_PATH_LITERAL("txt") },
    { FILE_PATH_LITERAL("text/css"), FILE_PATH_LITERAL("css") },
  };
#if defined(OS_POSIX)
  FilePath::StringType mime_type(contents_mime_type);
#elif defined(OS_WIN)
  FilePath::StringType mime_type(UTF8ToWide(contents_mime_type));
#endif  // OS_WIN
  for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(extensions); ++i) {
    if (mime_type == extensions[i].mime_type)
      return extensions[i].suggested_extension;
  }
  return FILE_PATH_LITERAL("");
}

Project: Chrome

void SavePackage::FinalizeDownloadEntry() {
  DCHECK(download_);
  DCHECK(download_manager_);

  NotificationService::current()->Notify(
      NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
      Source<DownloadManager>(download_manager_),
      Details<DownloadItem>(download_));
  StopObservation();
}

Project: Chrome

void SavePackage::Finish() {
  if (canceled())
    return;

  wait_state_ = SUCCESSFUL;
  finished_ = true;

  RecordSavePackageEvent(SAVE_PACKAGE_FINISHED);

  if (wrote_to_completed_file_) {
    RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_COMPLETED);
  }

  if (wrote_to_failed_file_) {
    RecordSavePackageEvent(SAVE_PACKAGE_WRITE_TO_FAILED);
  }

  SaveIDList save_ids;
  for (SaveUrlItemMap::iterator it = saved_failed_items_.begin();
       it != saved_failed_items_.end(); ++it)
    save_ids.push_back(it->second->save_id());

  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap,
                 file_manager_,
                 save_ids));

  if (download_) {
    if (download_->IsInProgress()) {
      if (save_type_ != SAVE_PAGE_TYPE_AS_MHTML) {
        download_->UpdateProgress(all_save_items_count_, CurrentSpeed(), "");
        download_->OnAllDataSaved(DownloadItem::kEmptyFileHash);
      }
      download_->MarkAsComplete();
    }
    FinalizeDownloadEntry();
  }
}

Project: Chrome

bool SavePackage::GenerateFileName(const std::string& disposition,
                                   const GURL& url,
                                   bool need_html_ext,
                                   FilePath::StringType* generated_name) {
  FilePath file_path = net::GenerateFileName(url, disposition, "", "", "",
                                             kDefaultSaveName);

  DCHECK(!file_path.empty());
  FilePath::StringType pure_file_name =
      file_path.RemoveExtension().BaseName().value();
  FilePath::StringType file_name_ext = file_path.Extension();

  if (need_html_ext) {
    file_name_ext = FILE_PATH_LITERAL(".");
    file_name_ext.append(kDefaultHtmlExtension);
  }

  uint32 max_path = GetMaxPathLengthForDirectory(saved_main_directory_path_);

  if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext,
                           max_path, &pure_file_name))
    return false;

  FilePath::StringType file_name = pure_file_name + file_name_ext;

  FileNameSet::const_iterator iter = file_name_set_.find(file_name);
  if (iter == file_name_set_.end()) {
    file_name_set_.insert(file_name);
  } else {
    pure_file_name =
        FilePath(*iter).RemoveExtension().BaseName().value();
    FilePath::StringType base_file_name = StripOrdinalNumber(pure_file_name);

    if (!GetSafePureFileName(saved_main_directory_path_, file_name_ext,
        max_path - kMaxFileOrdinalNumberPartLength, &base_file_name))
      return false;

    uint32 ordinal_number;
    FileNameCountMap::iterator it = file_name_count_map_.find(base_file_name);
    if (it == file_name_count_map_.end()) {
      file_name_count_map_[base_file_name] = 1;
      ordinal_number = 1;
    } else {
      ordinal_number = it->second;
    }

    if (ordinal_number > (kMaxFileOrdinalNumber - 1)) {
      FilePath temp_file;
      file_util::CreateTemporaryFile(&temp_file);
      file_name = temp_file.RemoveExtension().BaseName().value();
      if (!GetSafePureFileName(saved_main_directory_path_,
                               FilePath::StringType(),
                               max_path, &file_name))
        return false;
    } else {
      for (int i = ordinal_number; i < kMaxFileOrdinalNumber; ++i) {
        FilePath::StringType new_name = base_file_name +
            StringPrintf(FILE_PATH_LITERAL("(%d)"), i) + file_name_ext;
        if (file_name_set_.find(new_name) == file_name_set_.end()) {
          file_name = new_name;
          file_name_count_map_[base_file_name] = ++i;
          break;
        }
      }
    }

    file_name_set_.insert(file_name);
  }

  DCHECK(!file_name.empty());
  generated_name->assign(file_name);

  return true;
}

Project: Chrome

void SavePackage::GetAllSavableResourceLinksForCurrentPage() {
  if (wait_state_ != START_PROCESS)
    return;

  wait_state_ = RESOURCES_LIST;
  Send(new ViewMsg_GetAllSavableResourceLinksForCurrentPage(routing_id(),
                                                            page_url_));
}

Project: Chrome

uint32 SavePackage::GetMaxPathLengthForDirectory(const FilePath& base_dir) {
#if defined(OS_POSIX)
  return std::min(kMaxFilePathLength,
                  static_cast<uint32>(base_dir.value().length()) +
                  NAME_MAX + 1);
#else
  return kMaxFilePathLength;
#endif
}

Project: Chrome

bool SavePackage::GetSafePureFileName(const FilePath& dir_path,
                                      const FilePath::StringType& file_name_ext,
                                      uint32 max_file_path_len,
                                      FilePath::StringType* pure_file_name) {
  DCHECK(!pure_file_name->empty());
  int available_length = static_cast<int>(max_file_path_len -
                                          dir_path.value().length() -
                                          file_name_ext.length());
  if (!file_util::EndsWithSeparator(dir_path))
    --available_length;

  if (static_cast<int>(pure_file_name->length()) <= available_length)
    return true;

  if (available_length > 0) {
    *pure_file_name = pure_file_name->substr(0, available_length);
    return true;
  }

  pure_file_name->clear();
  return false;
}

Project: Chrome

void SavePackage::GetSaveInfo() {
  FilePath website_save_dir, download_save_dir;
  bool skip_dir_check;
  DCHECK(download_manager_);
  if (download_manager_->GetDelegate()) {
    download_manager_->GetDelegate()->GetSaveDir(
        web_contents()->GetBrowserContext(), &website_save_dir,
        &download_save_dir, &skip_dir_check);
  }
  std::string mime_type = web_contents()->GetContentsMimeType();
  std::string accept_languages =
      GetContentClient()->browser()->GetAcceptLangs(
          web_contents()->GetBrowserContext());

  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&SavePackage::CreateDirectoryOnFileThread, this,
          website_save_dir, download_save_dir, skip_dir_check,
          mime_type, accept_languages));
}

Project: Chrome

void SavePackage::GetSerializedHtmlDataForCurrentPageWithLocalLinks() {
  if (wait_state_ != HTML_DATA)
    return;
  std::vector<GURL> saved_links;
  std::vector<FilePath> saved_file_paths;
  int successful_started_items_count = 0;

  for (SaveUrlItemMap::iterator it = in_progress_items_.begin();
       it != in_progress_items_.end(); ++it) {
    DCHECK(it->second->save_source() ==
           SaveFileCreateInfo::SAVE_FILE_FROM_DOM);
    if (it->second->has_final_name())
      successful_started_items_count++;
    saved_links.push_back(it->second->url());
    saved_file_paths.push_back(it->second->file_name());
  }

  if (successful_started_items_count != in_process_count())
    return;

  for (SavedItemMap::iterator it = saved_success_items_.begin();
       it != saved_success_items_.end(); ++it) {
    DCHECK(it->second->has_final_name());
    saved_links.push_back(it->second->url());
    saved_file_paths.push_back(it->second->file_name());
  }

  FilePath relative_dir_name = saved_main_directory_path_.BaseName();

  Send(new ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks(
      routing_id(), saved_links, saved_file_paths, relative_dir_name));
}

Project: Chrome

FilePath SavePackage::GetSuggestedNameForSaveAs(
    bool can_save_as_complete,
    const std::string& contents_mime_type,
    const std::string& accept_langs) {
  FilePath name_with_proper_ext =
      FilePath::FromWStringHack(UTF16ToWideHack(title_));

  if (title_ == net::FormatUrl(page_url_, accept_langs)) {
    std::string url_path;
    if (!page_url_.SchemeIs(chrome::kDataScheme)) {
      std::vector<std::string> url_parts;
      base::SplitString(page_url_.path(), '/', &url_parts);
      if (!url_parts.empty()) {
        for (int i = static_cast<int>(url_parts.size()) - 1; i >= 0; --i) {
          url_path = url_parts[i];
          if (!url_path.empty())
            break;
        }
      }
      if (url_path.empty())
        url_path = page_url_.host();
    } else {
      url_path = "dataurl";
    }
    name_with_proper_ext = FilePath::FromWStringHack(UTF8ToWide(url_path));
  }

  name_with_proper_ext = EnsureMimeExtension(name_with_proper_ext,
                                             contents_mime_type);
  if (can_save_as_complete)
    name_with_proper_ext = EnsureHtmlExtension(name_with_proper_ext);

  FilePath::StringType file_name = name_with_proper_ext.value();
  file_util::ReplaceIllegalCharactersInPath(&file_name, ' ');
  return FilePath(file_name);
}

Project: Chrome

GURL SavePackage::GetUrlToBeSaved() {
  NavigationEntry* active_entry =
      web_contents()->GetController().GetActiveEntry();
  return active_entry->GetURL();
}

Project: Chrome

bool SavePackage::Init(
    const SavePackageDownloadCreatedCallback& download_created_callback) {
  if (wait_state_ != INITIALIZE)
    return false;

  wait_state_ = START_PROCESS;

  BrowserContext* browser_context = web_contents()->GetBrowserContext();
  if (!browser_context) {
    NOTREACHED();
    return false;
  }

  download_ = download_manager_->CreateSavePackageDownloadItem(
      saved_main_file_path_,
      page_url_,
      ((save_type_ == SAVE_PAGE_TYPE_AS_MHTML) ?
       "multipart/related" : "text/html"),
      this);
  if (!download_created_callback.is_null())
    download_created_callback.Run(download_);

  if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML) {
    DCHECK(!saved_main_directory_path_.empty());
    GetAllSavableResourceLinksForCurrentPage();
  } else if (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) {
    web_contents()->GenerateMHTML(saved_main_file_path_, base::Bind(
        &SavePackage::OnMHTMLGenerated, this));
  } else {
    wait_state_ = NET_FILES;
    SaveFileCreateInfo::SaveFileSource save_source = page_url_.SchemeIsFile() ?
        SaveFileCreateInfo::SAVE_FILE_FROM_FILE :
        SaveFileCreateInfo::SAVE_FILE_FROM_NET;
    SaveItem* save_item = new SaveItem(page_url_,
                                       Referrer(),
                                       this,
                                       save_source);
    waiting_item_queue_.push(save_item);
    all_save_items_count_ = 1;
    download_->SetTotalBytes(1);

    DoSavingProcess();
  }

  return true;
}

Project: Chrome

void SavePackage::InternalInit() {
  ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
  if (!rdh) {
    NOTREACHED();
    return;
  }

  file_manager_ = rdh->save_file_manager();
  DCHECK(file_manager_);

  download_manager_ = static_cast<DownloadManagerImpl*>(
      BrowserContext::GetDownloadManager(
          web_contents()->GetBrowserContext()));
  DCHECK(download_manager_);

  RecordSavePackageEvent(SAVE_PACKAGE_STARTED);
}

Project: Chrome

SaveItem* SavePackage::LookupItemInProcessBySaveId(int32 save_id) {
  if (in_process_count()) {
    for (SaveUrlItemMap::iterator it = in_progress_items_.begin();
        it != in_progress_items_.end(); ++it) {
      SaveItem* save_item = it->second;
      DCHECK(save_item->state() == SaveItem::IN_PROGRESS);
      if (save_item->save_id() == save_id)
        return save_item;
    }
  }
  return NULL;
}

Project: Chrome

void SavePackage::OnDownloadDestroyed(DownloadItem* download) {
  StopObservation();
}

Project: Chrome

void SavePackage::OnMHTMLGenerated(const FilePath& path, int64 size) {
  if (size <= 0) {
    Cancel(false);
    return;
  }
  wrote_to_completed_file_ = true;

  if (download_->IsInProgress()) {
    download_->SetTotalBytes(size);
    download_->UpdateProgress(size, 0, "");
    download_->OnAllDataSaved(DownloadItem::kEmptyFileHash);
  }

  if (!download_manager_->GetDelegate()) {
    Finish();
    return;
  }

  if (download_manager_->GetDelegate()->ShouldCompleteDownload(
          download_, base::Bind(&SavePackage::Finish, this))) {
    Finish();
  }
}

Project: Chrome

bool SavePackage::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(SavePackage, message)
    IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks,
                        OnReceivedSavableResourceLinksForCurrentPage)
    IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData,
                        OnReceivedSerializedHtmlData)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

Project: Chrome

void SavePackage::OnReceivedSerializedHtmlData(const GURL& frame_url,
                                               const std::string& data,
                                               int32 status) {
  WebPageSerializerClient::PageSerializationStatus flag =
      static_cast<WebPageSerializerClient::PageSerializationStatus>(status);
  if (wait_state_ != HTML_DATA)
    return;

  int id = contents_id();
  if (flag == WebPageSerializerClient::AllFramesAreFinished) {
    for (SaveUrlItemMap::iterator it = in_progress_items_.begin();
         it != in_progress_items_.end(); ++it) {
      VLOG(20) << " " << __FUNCTION__ << "()"
               << " save_id = " << it->second->save_id()
               << " url = \"" << it->second->url().spec() << "\"";
      BrowserThread::PostTask(
          BrowserThread::FILE, FROM_HERE,
          base::Bind(&SaveFileManager::SaveFinished,
                     file_manager_,
                     it->second->save_id(),
                     it->second->url(),
                     id,
                     true));
    }
    return;
  }

  SaveUrlItemMap::iterator it = in_progress_items_.find(frame_url.spec());
  if (it == in_progress_items_.end()) {
    for (SavedItemMap::iterator saved_it = saved_success_items_.begin();
      saved_it != saved_success_items_.end(); ++saved_it) {
      if (saved_it->second->url() == frame_url) {
        wrote_to_completed_file_ = true;
        break;
      }
    }

    it = saved_failed_items_.find(frame_url.spec());
    if (it != saved_failed_items_.end())
      wrote_to_failed_file_ = true;

    return;
  }

  SaveItem* save_item = it->second;
  DCHECK(save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM);

  if (!data.empty()) {
    scoped_refptr<net::IOBuffer> new_data(new net::IOBuffer(data.size()));
    memcpy(new_data->data(), data.data(), data.size());

    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        base::Bind(&SaveFileManager::UpdateSaveProgress,
                   file_manager_,
                   save_item->save_id(),
                   new_data,
                   static_cast<int>(data.size())));
  }

  if (flag == WebPageSerializerClient::CurrentFrameIsFinished) {
    VLOG(20) << " " << __FUNCTION__ << "()"
             << " save_id = " << save_item->save_id()
             << " url = \"" << save_item->url().spec() << "\"";
    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        base::Bind(&SaveFileManager::SaveFinished,
                   file_manager_,
                   save_item->save_id(),
                   save_item->url(),
                   id,
                   true));
  }
}

Project: Chrome

int SavePackage::PercentComplete() {
  if (!all_save_items_count_)
    return 0;
  else if (!in_process_count())
    return 100;
  else
    return completed_count() / all_save_items_count_;
}

Project: Chrome

void SavePackage::SaveCanceled(SaveItem* save_item) {
  file_manager_->RemoveSaveFile(save_item->save_id(),
                                save_item->url(),
                                this);
  if (save_item->save_id() != -1)
    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        base::Bind(&SaveFileManager::CancelSave,
                   file_manager_,
                   save_item->save_id()));
}

Project: Chrome

void SavePackage::SaveFailed(const GURL& save_url) {
  SaveUrlItemMap::iterator it = in_progress_items_.find(save_url.spec());
  if (it == in_progress_items_.end()) {
    NOTREACHED();  // Should not exist!
    return;
  }
  SaveItem* save_item = it->second;

  save_item->Finish(0, false);

  PutInProgressItemToSavedMap(save_item);

  if (download_ && download_->IsInProgress())
    download_->UpdateProgress(completed_count(), CurrentSpeed(), "");

  if ((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) ||
      (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) ||
      (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM)) {
    Cancel(true);
  }

  if (canceled()) {
    DCHECK(finished_);
    return;
  }

  DoSavingProcess();

  CheckFinish();
}

Project: Chrome

void SavePackage::SaveFinished(int32 save_id, int64 size, bool is_success) {
  SaveItem* save_item = LookupItemInProcessBySaveId(save_id);
  if (!save_item)
    return;

  save_item->Finish(size, is_success);
  file_manager_->RemoveSaveFile(save_id, save_item->url(), this);

  PutInProgressItemToSavedMap(save_item);

  if (download_ && download_->IsInProgress())
    download_->UpdateProgress(completed_count(), CurrentSpeed(), "");

  if (save_item->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_DOM &&
      save_item->url() == page_url_ && !save_item->received_bytes()) {
    Cancel(false);
    return;
  }

  if (canceled()) {
    DCHECK(finished_);
    return;
  }

  DoSavingProcess();

  CheckFinish();
}

Project: Chrome

void SavePackage::SaveNextFile(bool process_all_remaining_items) {
  DCHECK(web_contents());
  DCHECK(waiting_item_queue_.size());

  do {
    SaveItem* save_item = waiting_item_queue_.front();
    waiting_item_queue_.pop();

    SaveUrlItemMap::iterator it = in_progress_items_.find(
        save_item->url().spec());
    DCHECK(it == in_progress_items_.end());
    in_progress_items_[save_item->url().spec()] = save_item;
    save_item->Start();
    file_manager_->SaveURL(save_item->url(),
                           save_item->referrer(),
                           web_contents()->GetRenderProcessHost()->GetID(),
                           routing_id(),
                           save_item->save_source(),
                           save_item->full_path(),
                           web_contents()->
                               GetBrowserContext()->GetResourceContext(),
                           this);
  } while (process_all_remaining_items && waiting_item_queue_.size());
}

Project: Chrome

SavePackage::SavePackage(WebContents* web_contents,
                         SavePageType save_type,
                         const FilePath& file_full_path,
                         const FilePath& directory_full_path)
    : WebContentsObserver(web_contents),
      file_manager_(NULL),
      download_manager_(NULL),
      download_(NULL),
      page_url_(GetUrlToBeSaved()),
      saved_main_file_path_(file_full_path),
      saved_main_directory_path_(directory_full_path),
      title_(web_contents->GetTitle()),
      start_tick_(base::TimeTicks::Now()),
      finished_(false),
      mhtml_finishing_(false),
      user_canceled_(false),
      disk_error_occurred_(false),
      save_type_(save_type),
      all_save_items_count_(0),
      file_name_set_(&FilePath::CompareLessIgnoreCase),
      wait_state_(INITIALIZE),
      contents_id_(web_contents->GetRenderProcessHost()->GetID()),
      unique_id_(g_save_package_id++),
      wrote_to_completed_file_(false),
      wrote_to_failed_file_(false) {
  DCHECK(page_url_.is_valid());
  DCHECK((save_type_ == SAVE_PAGE_TYPE_AS_ONLY_HTML) ||
         (save_type_ == SAVE_PAGE_TYPE_AS_MHTML) ||
         (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
  DCHECK(!saved_main_file_path_.empty() &&
         saved_main_file_path_.value().length() <= kMaxFilePathLength);
  DCHECK(!saved_main_directory_path_.empty() &&
         saved_main_directory_path_.value().length() < kMaxFilePathLength);
  InternalInit();
}

Project: Chrome

SavePackage::SavePackage(WebContents* web_contents,
                         const FilePath& file_full_path,
                         const FilePath& directory_full_path)
    : WebContentsObserver(web_contents),
      file_manager_(NULL),
      download_manager_(NULL),
      download_(NULL),
      saved_main_file_path_(file_full_path),
      saved_main_directory_path_(directory_full_path),
      start_tick_(base::TimeTicks::Now()),
      finished_(true),
      mhtml_finishing_(false),
      user_canceled_(false),
      disk_error_occurred_(false),
      save_type_(SAVE_PAGE_TYPE_UNKNOWN),
      all_save_items_count_(0),
      file_name_set_(&FilePath::CompareLessIgnoreCase),
      wait_state_(INITIALIZE),
      contents_id_(0),
      unique_id_(g_save_package_id++),
      wrote_to_completed_file_(false),
      wrote_to_failed_file_(false) {
}

Project: Chrome

void SavePackage::StartSave(const SaveFileCreateInfo* info) {
  DCHECK(info && !info->url.is_empty());

  SaveUrlItemMap::iterator it = in_progress_items_.find(info->url.spec());
  if (it == in_progress_items_.end()) {
    DCHECK(canceled());
    return;
  }
  SaveItem* save_item = it->second;

  DCHECK(!saved_main_file_path_.empty());

  save_item->SetSaveId(info->save_id);
  save_item->SetTotalBytes(info->total_bytes);

  DCHECK(!save_item->has_final_name());
  if (info->url != page_url_) {
    FilePath::StringType generated_name;
    bool need_html_ext =
        info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM;
    if (!GenerateFileName(info->content_disposition,
                          GURL(info->url),
                          need_html_ext,
                          &generated_name)) {
      if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_DOM)
        Cancel(true);
      else
        SaveFinished(save_item->save_id(), 0, false);
      return;
    }

    DCHECK(save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML);
    DCHECK(!saved_main_directory_path_.empty());

    FilePath final_name = saved_main_directory_path_.Append(generated_name);
    save_item->Rename(final_name);
  } else {
    save_item->Rename(saved_main_file_path_);
  }

  if (info->save_source == SaveFileCreateInfo::SAVE_FILE_FROM_FILE) {
    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        base::Bind(&SaveFileManager::SaveLocalFile,
                   file_manager_,
                   save_item->url(),
                   save_item->save_id(),
                   contents_id()));
    return;
  }

  if (save_type_ == SAVE_PAGE_TYPE_AS_COMPLETE_HTML &&
      wait_state_ == HTML_DATA) {
    GetSerializedHtmlDataForCurrentPageWithLocalLinks();
  }
}

Project: Chrome

void SavePackage::Stop() {
  if (wait_state_ == INITIALIZE)
    return;

  DCHECK(canceled());
  if (in_process_count()) {
    SaveUrlItemMap::iterator it = in_progress_items_.begin();
    for (; it != in_progress_items_.end(); ++it) {
      SaveItem* save_item = it->second;
      DCHECK(save_item->state() == SaveItem::IN_PROGRESS);
      save_item->Cancel();
    }
    while (in_process_count())
      PutInProgressItemToSavedMap(in_progress_items_.begin()->second);
  }

  SaveIDList save_ids;
  for (SavedItemMap::iterator it = saved_success_items_.begin();
      it != saved_success_items_.end(); ++it)
    save_ids.push_back(it->first);
  for (SaveUrlItemMap::iterator it = saved_failed_items_.begin();
      it != saved_failed_items_.end(); ++it)
    save_ids.push_back(it->second->save_id());

  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&SaveFileManager::RemoveSavedFileFromFileMap,
                 file_manager_,
                 save_ids));

  finished_ = true;
  wait_state_ = FAILED;

  if (download_) {
    download_->Cancel(false);
    FinalizeDownloadEntry();
  }
}

Project: Chrome

void SavePackage::StopObservation() {
  DCHECK(download_);
  DCHECK(download_manager_);

  download_->RemoveObserver(this);
  download_ = NULL;
  download_manager_ = NULL;
}

Project: Chrome

FilePath::StringType StripOrdinalNumber(
    const FilePath::StringType& pure_file_name) {
  FilePath::StringType::size_type r_paren_index =
      pure_file_name.rfind(FILE_PATH_LITERAL(')'));
  FilePath::StringType::size_type l_paren_index =
      pure_file_name.rfind(FILE_PATH_LITERAL('('));
  if (l_paren_index >= r_paren_index)
    return pure_file_name;

  for (FilePath::StringType::size_type i = l_paren_index + 1;
       i != r_paren_index; ++i) {
    if (!IsAsciiDigit(pure_file_name[i]))
      return pure_file_name;
  }

  return pure_file_name.substr(0, l_paren_index);
}

Project: Chrome

bool SavePackage::UpdateSaveProgress(int32 save_id,
                                     int64 size,
                                     bool write_success) {
  SaveItem* save_item = LookupItemInProcessBySaveId(save_id);
  if (!save_item)
    return false;

  save_item->Update(size);

  if (!write_success) {
    Cancel(false);
  }
  return true;
}

Project: Chrome

WebContents* SavePackage::web_contents() const {
  return WebContentsObserver::web_contents();
}

Project: Chrome

SavePackage::~SavePackage() {
  if (!finished_ && !canceled()) {
    Cancel(true);
  }

  CHECK(!download_);

  DCHECK(all_save_items_count_ == (waiting_item_queue_.size() +
                                   completed_count() +
                                   in_process_count()));
  while (!waiting_item_queue_.empty()) {
    SaveItem* save_item = waiting_item_queue_.front();
    waiting_item_queue_.pop();
    delete save_item;
  }

  STLDeleteValues(&saved_success_items_);
  STLDeleteValues(&in_progress_items_);
  STLDeleteValues(&saved_failed_items_);

  file_manager_ = NULL;
}