chromium/ios/chrome/browser/sharing/model/share_file_download_tab_helper.mm

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/sharing/model/share_file_download_tab_helper.h"

#import "base/memory/ptr_util.h"
#import "base/metrics/histogram_functions.h"
#import "base/metrics/user_metrics.h"
#import "base/metrics/user_metrics_action.h"
#import "base/strings/sys_string_conversions.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ios/web/public/navigation/navigation_context.h"
#import "ios/web/public/navigation/navigation_item.h"
#import "ios/web/public/navigation/navigation_manager.h"
#import "ios/web/public/web_state.h"
#import "net/base/filename_util.h"
#import "net/http/http_response_headers.h"
#import "ui/base/l10n/l10n_util.h"
#import "url/gurl.h"

namespace content_type {

const char kMimeTypeMicrosoftPowerPointOpenXML[] =
    "application/vnd.openxmlformats-officedocument.presentationml.presentation";

const char kMimeTypeMicrosoftWordOpenXML[] =
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document";

const char kMimeTypeMicrosoftExcelOpenXML[] =
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

const char kMimeTypePDF[] = "application/pdf";

const char kMimeTypeMicrosoftWord[] = "application/msword";

const char kMimeTypeJPEG[] = "image/jpeg";

const char kMimeTypePNG[] = "image/png";

const char kMimeTypeMicrosoftPowerPoint[] = "application/vnd.ms-powerpoint";

const char kMimeTypeRTF[] = "application/rtf";

const char kMimeTypeSVG[] = "image/svg+xml";

const char kMimeTypeMicrosoftExcel[] = "application/vnd.ms-excel";

}  // namespace content_type

ShareFileDownloadTabHelper::~ShareFileDownloadTabHelper() {
  // In case that the destructor is called before WebStateDestroyed. stop
  // observing the WebState.
  if (web_state_) {
    web_state_->RemoveObserver(this);
    web_state_ = nullptr;
  }
}

ShareFileDownloadMimeType ShareFileDownloadTabHelper::GetUmaResult(
    const std::string& mime_type) const {
  if (mime_type == content_type::kMimeTypePDF) {
    return ShareFileDownloadMimeType::kMimeTypePDF;
  }
  if (mime_type == content_type::kMimeTypeMicrosoftWord) {
    return ShareFileDownloadMimeType::kMimeTypeMicrosoftWord;
  }
  if (mime_type == content_type::kMimeTypeMicrosoftWordOpenXML) {
    return ShareFileDownloadMimeType::kMimeTypeMicrosoftWordOpenXML;
  }
  if (mime_type == content_type::kMimeTypeJPEG) {
    return ShareFileDownloadMimeType::kMimeTypeJPEG;
  }
  if (mime_type == content_type::kMimeTypePNG) {
    return ShareFileDownloadMimeType::kMimeTypePNG;
  }
  if (mime_type == content_type::kMimeTypeMicrosoftPowerPoint) {
    return ShareFileDownloadMimeType::kMimeTypeMicrosoftPowerPoint;
  }
  if (mime_type == content_type::kMimeTypeMicrosoftPowerPointOpenXML) {
    return ShareFileDownloadMimeType::kMimeTypeMicrosoftPowerPointOpenXML;
  }
  if (mime_type == content_type::kMimeTypeRTF) {
    return ShareFileDownloadMimeType::kMimeTypeRTF;
  }
  if (mime_type == content_type::kMimeTypeSVG) {
    return ShareFileDownloadMimeType::kMimeTypeSVG;
  }
  if (mime_type == content_type::kMimeTypeMicrosoftExcel) {
    return ShareFileDownloadMimeType::kMimeTypeMicrosoftExcel;
  }
  if (mime_type == content_type::kMimeTypeMicrosoftExcelOpenXML) {
    return ShareFileDownloadMimeType::kMimeTypeMicrosoftExcelOpenXML;
  }
  return ShareFileDownloadMimeType::kMimeTypeNotHandled;
}

void ShareFileDownloadTabHelper::HandleExportableFile() {
  ShareFileDownloadMimeType mime_type =
      GetUmaResult(web_state_->GetContentsMimeType());
  if (mime_type == ShareFileDownloadMimeType::kMimeTypeNotHandled) {
    return;
  }

  CHECK_NE(mime_type, ShareFileDownloadMimeType::kMimeTypeNotHandled);
  base::UmaHistogramEnumeration("IOS.OpenIn.MimeType", mime_type);
}

void ShareFileDownloadTabHelper::DidFinishNavigation(
    web::WebState* web_state,
    web::NavigationContext* navigation_context) {
  // Retrieve the response headers to be used in case the Page loaded
  // successfully (PageLoaded WebStateObserver method will always be called
  // immediatly after DidFinishNavigation).
  response_headers_ = scoped_refptr<net::HttpResponseHeaders>(
      navigation_context->GetResponseHeaders());
}

ShareFileDownloadTabHelper::ShareFileDownloadTabHelper(web::WebState* web_state)
    : web_state_(web_state) {
  web_state_->AddObserver(this);
}

void ShareFileDownloadTabHelper::PageLoaded(
    web::WebState* web_state,
    web::PageLoadCompletionStatus load_completion_status) {
  if (load_completion_status == web::PageLoadCompletionStatus::SUCCESS) {
    HandleExportableFile();
  }
}

void ShareFileDownloadTabHelper::WebStateDestroyed(web::WebState* web_state) {
  DCHECK_EQ(web_state_, web_state);
  // The call to RemoveUserData cause the destruction of the current instance,
  // so nothing should be done after that point (this is like "delete this;").
  // Unregistration as an observer happens in the destructor.
  web_state_->RemoveUserData(UserDataKey());
}

std::u16string ShareFileDownloadTabHelper::GetFileNameSuggestion() {
  // Try to generate a filename by first looking at `content_disposition`, then
  // at the last component of WebState's last committed URL and if both of these
  // fail use the default filename "document".
  std::string content_disposition;
  if (response_headers_) {
    response_headers_->GetNormalizedHeader("content-disposition",
                                           &content_disposition);
  }
  std::string default_file_name =
      l10n_util::GetStringUTF8(IDS_IOS_OPEN_IN_FILE_DEFAULT_TITLE);
  web::NavigationItem* item =
      web_state_->GetNavigationManager()->GetLastCommittedItem();
  const GURL& last_committed_url = item ? item->GetURL() : GURL();
  std::u16string file_name =
      net::GetSuggestedFilename(last_committed_url, content_disposition,
                                "",  // referrer-charset
                                "",  // suggested-name
                                web_state_->GetContentsMimeType(),  // mime-type
                                default_file_name);
  return file_name;
}

// static
bool ShareFileDownloadTabHelper::ShouldDownload(web::WebState* web_state) {
  if (!web_state) {
    return false;
  }

  std::string mime_type = web_state->GetContentsMimeType();
  return (mime_type == content_type::kMimeTypePDF ||
          mime_type == content_type::kMimeTypeMicrosoftWord ||
          mime_type == content_type::kMimeTypeMicrosoftWordOpenXML ||
          mime_type == content_type::kMimeTypeJPEG ||
          mime_type == content_type::kMimeTypePNG ||
          mime_type == content_type::kMimeTypeMicrosoftPowerPoint ||
          mime_type == content_type::kMimeTypeMicrosoftPowerPointOpenXML ||
          mime_type == content_type::kMimeTypeRTF ||
          mime_type == content_type::kMimeTypeSVG ||
          mime_type == content_type::kMimeTypeMicrosoftExcel ||
          mime_type == content_type::kMimeTypeMicrosoftExcelOpenXML);
}

WEB_STATE_USER_DATA_KEY_IMPL(ShareFileDownloadTabHelper)