OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Implements the Chrome Extensions Media Galleries API. | 5 // Implements the Chrome Extensions Media Galleries API. |
6 | 6 |
7 #include "chrome/browser/extensions/api/media_galleries/media_galleries_api.h" | 7 #include "chrome/browser/extensions/api/media_galleries/media_galleries_api.h" |
8 | 8 |
9 #include <set> | 9 #include <set> |
10 #include <string> | 10 #include <string> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "apps/app_window.h" | 13 #include "apps/app_window.h" |
14 #include "apps/app_window_registry.h" | 14 #include "apps/app_window_registry.h" |
15 #include "base/callback.h" | 15 #include "base/callback.h" |
16 #include "base/lazy_instance.h" | 16 #include "base/lazy_instance.h" |
| 17 #include "base/numerics/safe_conversions.h" |
17 #include "base/stl_util.h" | 18 #include "base/stl_util.h" |
18 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
19 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
20 #include "base/values.h" | 21 #include "base/values.h" |
21 #include "chrome/browser/browser_process.h" | 22 #include "chrome/browser/browser_process.h" |
22 #include "chrome/browser/extensions/api/file_system/file_system_api.h" | 23 #include "chrome/browser/extensions/api/file_system/file_system_api.h" |
23 #include "chrome/browser/extensions/blob_reader.h" | 24 #include "chrome/browser/extensions/blob_reader.h" |
24 #include "chrome/browser/extensions/extension_tab_util.h" | 25 #include "chrome/browser/extensions/extension_tab_util.h" |
25 #include "chrome/browser/media_galleries/fileapi/safe_media_metadata_parser.h" | 26 #include "chrome/browser/media_galleries/fileapi/safe_media_metadata_parser.h" |
26 #include "chrome/browser/media_galleries/media_file_system_registry.h" | 27 #include "chrome/browser/media_galleries/media_file_system_registry.h" |
27 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h" | 28 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h" |
28 #include "chrome/browser/media_galleries/media_galleries_histograms.h" | 29 #include "chrome/browser/media_galleries/media_galleries_histograms.h" |
29 #include "chrome/browser/media_galleries/media_galleries_preferences.h" | 30 #include "chrome/browser/media_galleries/media_galleries_preferences.h" |
30 #include "chrome/browser/media_galleries/media_galleries_scan_result_dialog_cont
roller.h" | 31 #include "chrome/browser/media_galleries/media_galleries_scan_result_dialog_cont
roller.h" |
31 #include "chrome/browser/media_galleries/media_scan_manager.h" | 32 #include "chrome/browser/media_galleries/media_scan_manager.h" |
32 #include "chrome/browser/platform_util.h" | 33 #include "chrome/browser/platform_util.h" |
33 #include "chrome/browser/profiles/profile.h" | 34 #include "chrome/browser/profiles/profile.h" |
34 #include "chrome/browser/ui/chrome_select_file_policy.h" | 35 #include "chrome/browser/ui/chrome_select_file_policy.h" |
35 #include "chrome/common/extensions/api/media_galleries.h" | 36 #include "chrome/common/extensions/api/media_galleries.h" |
36 #include "chrome/common/pref_names.h" | 37 #include "chrome/common/pref_names.h" |
37 #include "components/storage_monitor/storage_info.h" | 38 #include "components/storage_monitor/storage_info.h" |
38 #include "components/web_modal/web_contents_modal_dialog_manager.h" | 39 #include "components/web_modal/web_contents_modal_dialog_manager.h" |
| 40 #include "content/public/browser/blob_handle.h" |
| 41 #include "content/public/browser/browser_context.h" |
39 #include "content/public/browser/browser_thread.h" | 42 #include "content/public/browser/browser_thread.h" |
40 #include "content/public/browser/child_process_security_policy.h" | 43 #include "content/public/browser/child_process_security_policy.h" |
41 #include "content/public/browser/render_process_host.h" | 44 #include "content/public/browser/render_process_host.h" |
42 #include "content/public/browser/render_view_host.h" | 45 #include "content/public/browser/render_view_host.h" |
43 #include "content/public/browser/web_contents.h" | 46 #include "content/public/browser/web_contents.h" |
| 47 #include "extensions/browser/blob_holder.h" |
44 #include "extensions/browser/event_router.h" | 48 #include "extensions/browser/event_router.h" |
45 #include "extensions/browser/extension_prefs.h" | 49 #include "extensions/browser/extension_prefs.h" |
46 #include "extensions/browser/extension_system.h" | 50 #include "extensions/browser/extension_system.h" |
47 #include "extensions/common/extension.h" | 51 #include "extensions/common/extension.h" |
48 #include "extensions/common/permissions/api_permission.h" | 52 #include "extensions/common/permissions/api_permission.h" |
49 #include "extensions/common/permissions/media_galleries_permission.h" | 53 #include "extensions/common/permissions/media_galleries_permission.h" |
50 #include "extensions/common/permissions/permissions_data.h" | 54 #include "extensions/common/permissions/permissions_data.h" |
51 #include "grit/generated_resources.h" | 55 #include "grit/generated_resources.h" |
52 #include "net/base/mime_sniffer.h" | 56 #include "net/base/mime_sniffer.h" |
53 #include "ui/base/l10n/l10n_util.h" | 57 #include "ui/base/l10n/l10n_util.h" |
| 58 #include "webkit/browser/blob/blob_data_handle.h" |
54 | 59 |
55 using content::WebContents; | 60 using content::WebContents; |
56 using storage_monitor::MediaStorageUtil; | 61 using storage_monitor::MediaStorageUtil; |
57 using storage_monitor::StorageInfo; | 62 using storage_monitor::StorageInfo; |
58 using web_modal::WebContentsModalDialogManager; | 63 using web_modal::WebContentsModalDialogManager; |
59 | 64 |
60 namespace extensions { | 65 namespace extensions { |
61 | 66 |
62 namespace MediaGalleries = api::media_galleries; | 67 namespace MediaGalleries = api::media_galleries; |
63 namespace DropPermissionForMediaFileSystem = | 68 namespace DropPermissionForMediaFileSystem = |
(...skipping 11 matching lines...) Expand all Loading... |
75 const char kNonExistentGalleryId[] = "Non-existent gallery id."; | 80 const char kNonExistentGalleryId[] = "Non-existent gallery id."; |
76 const char kNoScanPermission[] = "No permission to scan."; | 81 const char kNoScanPermission[] = "No permission to scan."; |
77 | 82 |
78 const char kDeviceIdKey[] = "deviceId"; | 83 const char kDeviceIdKey[] = "deviceId"; |
79 const char kGalleryIdKey[] = "galleryId"; | 84 const char kGalleryIdKey[] = "galleryId"; |
80 const char kIsAvailableKey[] = "isAvailable"; | 85 const char kIsAvailableKey[] = "isAvailable"; |
81 const char kIsMediaDeviceKey[] = "isMediaDevice"; | 86 const char kIsMediaDeviceKey[] = "isMediaDevice"; |
82 const char kIsRemovableKey[] = "isRemovable"; | 87 const char kIsRemovableKey[] = "isRemovable"; |
83 const char kNameKey[] = "name"; | 88 const char kNameKey[] = "name"; |
84 | 89 |
| 90 const char kMetadataKey[] = "metadata"; |
| 91 const char kAttachedImagesBlobInfoKey[] = "attachedImagesBlobInfo"; |
| 92 const char kBlobUUIDKey[] = "blobUUID"; |
| 93 const char kTypeKey[] = "type"; |
| 94 const char kSizeKey[] = "size"; |
| 95 |
85 MediaFileSystemRegistry* media_file_system_registry() { | 96 MediaFileSystemRegistry* media_file_system_registry() { |
86 return g_browser_process->media_file_system_registry(); | 97 return g_browser_process->media_file_system_registry(); |
87 } | 98 } |
88 | 99 |
89 MediaScanManager* media_scan_manager() { | 100 MediaScanManager* media_scan_manager() { |
90 return media_file_system_registry()->media_scan_manager(); | 101 return media_file_system_registry()->media_scan_manager(); |
91 } | 102 } |
92 | 103 |
93 // Checks whether the MediaGalleries API is currently accessible (it may be | 104 // Checks whether the MediaGalleries API is currently accessible (it may be |
94 // disallowed even if an extension has the requisite permission). Then | 105 // disallowed even if an extension has the requisite permission). Then |
(...skipping 719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
814 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &blob_uuid)); | 825 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &blob_uuid)); |
815 | 826 |
816 const base::Value* options_value = NULL; | 827 const base::Value* options_value = NULL; |
817 if (!args_->Get(1, &options_value)) | 828 if (!args_->Get(1, &options_value)) |
818 return false; | 829 return false; |
819 scoped_ptr<MediaGalleries::MediaMetadataOptions> options = | 830 scoped_ptr<MediaGalleries::MediaMetadataOptions> options = |
820 MediaGalleries::MediaMetadataOptions::FromValue(*options_value); | 831 MediaGalleries::MediaMetadataOptions::FromValue(*options_value); |
821 if (!options) | 832 if (!options) |
822 return false; | 833 return false; |
823 | 834 |
824 bool mime_type_only = options->metadata_type == | |
825 MediaGalleries::GET_METADATA_TYPE_MIMETYPEONLY; | |
826 | |
827 return Setup(GetProfile(), &error_, base::Bind( | 835 return Setup(GetProfile(), &error_, base::Bind( |
828 &MediaGalleriesGetMetadataFunction::OnPreferencesInit, this, | 836 &MediaGalleriesGetMetadataFunction::OnPreferencesInit, this, |
829 mime_type_only, blob_uuid)); | 837 options->metadata_type, blob_uuid)); |
830 } | 838 } |
831 | 839 |
832 void MediaGalleriesGetMetadataFunction::OnPreferencesInit( | 840 void MediaGalleriesGetMetadataFunction::OnPreferencesInit( |
833 bool mime_type_only, const std::string& blob_uuid) { | 841 MediaGalleries::GetMetadataType metadata_type, |
| 842 const std::string& blob_uuid) { |
834 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 843 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
835 | 844 |
836 // BlobReader is self-deleting. | 845 // BlobReader is self-deleting. |
837 BlobReader* reader = new BlobReader( | 846 BlobReader* reader = new BlobReader( |
838 GetProfile(), | 847 GetProfile(), |
839 blob_uuid, | 848 blob_uuid, |
840 base::Bind(&MediaGalleriesGetMetadataFunction::SniffMimeType, this, | 849 base::Bind(&MediaGalleriesGetMetadataFunction::GetMetadata, this, |
841 mime_type_only, blob_uuid)); | 850 metadata_type, blob_uuid)); |
842 reader->SetByteRange(0, net::kMaxBytesToSniff); | 851 reader->SetByteRange(0, net::kMaxBytesToSniff); |
843 reader->Start(); | 852 reader->Start(); |
844 } | 853 } |
845 | 854 |
846 void MediaGalleriesGetMetadataFunction::SniffMimeType( | 855 void MediaGalleriesGetMetadataFunction::GetMetadata( |
847 bool mime_type_only, const std::string& blob_uuid, | 856 MediaGalleries::GetMetadataType metadata_type, const std::string& blob_uuid, |
848 scoped_ptr<std::string> blob_header, int64 total_blob_length) { | 857 scoped_ptr<std::string> blob_header, int64 total_blob_length) { |
849 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 858 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
850 | 859 |
851 std::string mime_type; | 860 std::string mime_type; |
852 bool mime_type_sniffed = net::SniffMimeTypeFromLocalData( | 861 bool mime_type_sniffed = net::SniffMimeTypeFromLocalData( |
853 blob_header->c_str(), blob_header->size(), &mime_type); | 862 blob_header->c_str(), blob_header->size(), &mime_type); |
854 | 863 |
855 if (!mime_type_sniffed) { | 864 if (!mime_type_sniffed) { |
856 SendResponse(false); | 865 SendResponse(false); |
857 return; | 866 return; |
858 } | 867 } |
859 | 868 |
860 if (mime_type_only) { | 869 if (metadata_type == MediaGalleries::GET_METADATA_TYPE_MIMETYPEONLY) { |
861 MediaGalleries::MediaMetadata metadata; | 870 MediaGalleries::MediaMetadata metadata; |
862 metadata.mime_type = mime_type; | 871 metadata.mime_type = mime_type; |
863 SetResult(metadata.ToValue().release()); | 872 |
| 873 base::DictionaryValue* result_dictionary = new base::DictionaryValue; |
| 874 result_dictionary->Set(kMetadataKey, metadata.ToValue().release()); |
| 875 SetResult(result_dictionary); |
864 SendResponse(true); | 876 SendResponse(true); |
865 return; | 877 return; |
866 } | 878 } |
867 | 879 |
868 // TODO(tommycli): Enable getting attached images. | 880 // We get attached images by default. GET_METADATA_TYPE_NONE is the default |
| 881 // value if the caller doesn't specify the metadata type. |
| 882 bool get_attached_images = |
| 883 metadata_type == MediaGalleries::GET_METADATA_TYPE_ALL || |
| 884 metadata_type == MediaGalleries::GET_METADATA_TYPE_NONE; |
| 885 |
869 scoped_refptr<metadata::SafeMediaMetadataParser> parser( | 886 scoped_refptr<metadata::SafeMediaMetadataParser> parser( |
870 new metadata::SafeMediaMetadataParser(GetProfile(), blob_uuid, | 887 new metadata::SafeMediaMetadataParser(GetProfile(), blob_uuid, |
871 total_blob_length, mime_type, | 888 total_blob_length, mime_type, |
872 false /* get_attached_images */)); | 889 get_attached_images)); |
873 parser->Start(base::Bind( | 890 parser->Start(base::Bind( |
874 &MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone, this)); | 891 &MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone, this)); |
875 } | 892 } |
876 | 893 |
877 void MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone( | 894 void MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone( |
878 bool parse_success, scoped_ptr<base::DictionaryValue> metadata_dictionary, | 895 bool parse_success, scoped_ptr<base::DictionaryValue> metadata_dictionary, |
879 scoped_ptr<std::vector<metadata::AttachedImage> > attached_images) { | 896 scoped_ptr<std::vector<metadata::AttachedImage> > attached_images) { |
| 897 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 898 |
880 if (!parse_success) { | 899 if (!parse_success) { |
881 SendResponse(false); | 900 SendResponse(false); |
882 return; | 901 return; |
883 } | 902 } |
884 | 903 |
885 SetResult(metadata_dictionary->DeepCopy()); | 904 DCHECK(metadata_dictionary.get()); |
| 905 DCHECK(attached_images.get()); |
| 906 |
| 907 scoped_ptr<base::DictionaryValue> result_dictionary( |
| 908 new base::DictionaryValue); |
| 909 result_dictionary->Set(kMetadataKey, metadata_dictionary.release()); |
| 910 |
| 911 if (attached_images->empty()) { |
| 912 SetResult(result_dictionary.release()); |
| 913 SendResponse(true); |
| 914 return; |
| 915 } |
| 916 |
| 917 result_dictionary->Set(kAttachedImagesBlobInfoKey, new base::ListValue); |
| 918 metadata::AttachedImage* first_image = &attached_images->front(); |
| 919 content::BrowserContext::CreateMemoryBackedBlob( |
| 920 GetProfile(), |
| 921 first_image->data.c_str(), |
| 922 first_image->data.size(), |
| 923 base::Bind(&MediaGalleriesGetMetadataFunction::ConstructNextBlob, |
| 924 this, base::Passed(&result_dictionary), |
| 925 base::Passed(&attached_images), |
| 926 base::Passed(make_scoped_ptr(new std::vector<std::string>)))); |
| 927 } |
| 928 |
| 929 void MediaGalleriesGetMetadataFunction::ConstructNextBlob( |
| 930 scoped_ptr<base::DictionaryValue> result_dictionary, |
| 931 scoped_ptr<std::vector<metadata::AttachedImage> > attached_images, |
| 932 scoped_ptr<std::vector<std::string> > blob_uuids, |
| 933 scoped_ptr<content::BlobHandle> current_blob) { |
| 934 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 935 |
| 936 DCHECK(result_dictionary.get()); |
| 937 DCHECK(attached_images.get()); |
| 938 DCHECK(blob_uuids.get()); |
| 939 DCHECK(current_blob.get()); |
| 940 |
| 941 DCHECK(!attached_images->empty()); |
| 942 DCHECK_LT(blob_uuids->size(), attached_images->size()); |
| 943 |
| 944 // For the newly constructed Blob, store its image's metadata and Blob UUID. |
| 945 base::ListValue* attached_images_list = NULL; |
| 946 result_dictionary->GetList(kAttachedImagesBlobInfoKey, &attached_images_list); |
| 947 DCHECK(attached_images_list); |
| 948 DCHECK_LT(attached_images_list->GetSize(), attached_images->size()); |
| 949 |
| 950 metadata::AttachedImage* current_image = |
| 951 &(*attached_images)[blob_uuids->size()]; |
| 952 base::DictionaryValue* attached_image = new base::DictionaryValue; |
| 953 attached_image->Set(kBlobUUIDKey, new base::StringValue( |
| 954 current_blob->GetUUID())); |
| 955 attached_image->Set(kTypeKey, new base::StringValue( |
| 956 current_image->type)); |
| 957 attached_image->Set(kSizeKey, new base::FundamentalValue( |
| 958 base::checked_cast<int>(current_image->data.size()))); |
| 959 attached_images_list->Append(attached_image); |
| 960 |
| 961 blob_uuids->push_back(current_blob->GetUUID()); |
| 962 WebContents* contents = WebContents::FromRenderViewHost(render_view_host()); |
| 963 extensions::BlobHolder* holder = |
| 964 extensions::BlobHolder::FromRenderProcessHost( |
| 965 contents->GetRenderProcessHost()); |
| 966 holder->HoldBlobReference(current_blob.Pass()); |
| 967 |
| 968 // Construct the next Blob if necessary. |
| 969 if (blob_uuids->size() < attached_images->size()) { |
| 970 metadata::AttachedImage* next_image = |
| 971 &(*attached_images)[blob_uuids->size()]; |
| 972 content::BrowserContext::CreateMemoryBackedBlob( |
| 973 GetProfile(), |
| 974 next_image->data.c_str(), |
| 975 next_image->data.size(), |
| 976 base::Bind(&MediaGalleriesGetMetadataFunction::ConstructNextBlob, |
| 977 this, base::Passed(&result_dictionary), |
| 978 base::Passed(&attached_images), base::Passed(&blob_uuids))); |
| 979 return; |
| 980 } |
| 981 |
| 982 // All Blobs have been constructed. The renderer will take ownership. |
| 983 SetResult(result_dictionary.release()); |
| 984 SetTransferredBlobUUIDs(*blob_uuids); |
886 SendResponse(true); | 985 SendResponse(true); |
887 } | 986 } |
888 | 987 |
889 } // namespace extensions | 988 } // namespace extensions |
OLD | NEW |