| // 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/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" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| 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::EmptyGURL(); |
| 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) |