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/platform_file.h" | 18 #include "base/platform_file.h" |
18 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
19 #include "base/strings/string_number_conversions.h" | 20 #include "base/strings/string_number_conversions.h" |
20 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
21 #include "base/values.h" | 22 #include "base/values.h" |
22 #include "chrome/browser/browser_process.h" | 23 #include "chrome/browser/browser_process.h" |
23 #include "chrome/browser/extensions/api/file_system/file_system_api.h" | 24 #include "chrome/browser/extensions/api/file_system/file_system_api.h" |
25 #include "chrome/browser/extensions/blob_holder.h" | |
24 #include "chrome/browser/extensions/blob_reader.h" | 26 #include "chrome/browser/extensions/blob_reader.h" |
25 #include "chrome/browser/extensions/extension_tab_util.h" | 27 #include "chrome/browser/extensions/extension_tab_util.h" |
26 #include "chrome/browser/media_galleries/fileapi/safe_media_metadata_parser.h" | 28 #include "chrome/browser/media_galleries/fileapi/safe_media_metadata_parser.h" |
27 #include "chrome/browser/media_galleries/media_file_system_registry.h" | 29 #include "chrome/browser/media_galleries/media_file_system_registry.h" |
28 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h" | 30 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h" |
29 #include "chrome/browser/media_galleries/media_galleries_histograms.h" | 31 #include "chrome/browser/media_galleries/media_galleries_histograms.h" |
30 #include "chrome/browser/media_galleries/media_galleries_preferences.h" | 32 #include "chrome/browser/media_galleries/media_galleries_preferences.h" |
31 #include "chrome/browser/media_galleries/media_galleries_scan_result_dialog_cont roller.h" | 33 #include "chrome/browser/media_galleries/media_galleries_scan_result_dialog_cont roller.h" |
32 #include "chrome/browser/media_galleries/media_scan_manager.h" | 34 #include "chrome/browser/media_galleries/media_scan_manager.h" |
33 #include "chrome/browser/platform_util.h" | 35 #include "chrome/browser/platform_util.h" |
34 #include "chrome/browser/profiles/profile.h" | 36 #include "chrome/browser/profiles/profile.h" |
35 #include "chrome/browser/ui/chrome_select_file_policy.h" | 37 #include "chrome/browser/ui/chrome_select_file_policy.h" |
36 #include "chrome/common/extensions/api/media_galleries.h" | 38 #include "chrome/common/extensions/api/media_galleries.h" |
37 #include "chrome/common/pref_names.h" | 39 #include "chrome/common/pref_names.h" |
38 #include "components/storage_monitor/storage_info.h" | 40 #include "components/storage_monitor/storage_info.h" |
39 #include "components/web_modal/web_contents_modal_dialog_manager.h" | 41 #include "components/web_modal/web_contents_modal_dialog_manager.h" |
42 #include "content/public/browser/browser_context.h" | |
40 #include "content/public/browser/browser_thread.h" | 43 #include "content/public/browser/browser_thread.h" |
41 #include "content/public/browser/child_process_security_policy.h" | 44 #include "content/public/browser/child_process_security_policy.h" |
45 #include "content/public/browser/fileapi/blob_context.h" | |
42 #include "content/public/browser/render_process_host.h" | 46 #include "content/public/browser/render_process_host.h" |
43 #include "content/public/browser/render_view_host.h" | 47 #include "content/public/browser/render_view_host.h" |
44 #include "content/public/browser/web_contents.h" | 48 #include "content/public/browser/web_contents.h" |
45 #include "extensions/browser/event_router.h" | 49 #include "extensions/browser/event_router.h" |
46 #include "extensions/browser/extension_prefs.h" | 50 #include "extensions/browser/extension_prefs.h" |
47 #include "extensions/browser/extension_system.h" | 51 #include "extensions/browser/extension_system.h" |
48 #include "extensions/common/extension.h" | 52 #include "extensions/common/extension.h" |
49 #include "extensions/common/permissions/api_permission.h" | 53 #include "extensions/common/permissions/api_permission.h" |
50 #include "extensions/common/permissions/media_galleries_permission.h" | 54 #include "extensions/common/permissions/media_galleries_permission.h" |
51 #include "extensions/common/permissions/permissions_data.h" | 55 #include "extensions/common/permissions/permissions_data.h" |
52 #include "grit/generated_resources.h" | 56 #include "grit/generated_resources.h" |
53 #include "net/base/mime_sniffer.h" | 57 #include "net/base/mime_sniffer.h" |
54 #include "ui/base/l10n/l10n_util.h" | 58 #include "ui/base/l10n/l10n_util.h" |
59 #include "webkit/browser/blob/blob_data_handle.h" | |
55 | 60 |
56 using content::WebContents; | 61 using content::WebContents; |
57 using storage_monitor::MediaStorageUtil; | 62 using storage_monitor::MediaStorageUtil; |
58 using storage_monitor::StorageInfo; | 63 using storage_monitor::StorageInfo; |
59 using web_modal::WebContentsModalDialogManager; | 64 using web_modal::WebContentsModalDialogManager; |
60 | 65 |
61 namespace extensions { | 66 namespace extensions { |
62 | 67 |
63 namespace MediaGalleries = api::media_galleries; | 68 namespace MediaGalleries = api::media_galleries; |
64 namespace DropPermissionForMediaFileSystem = | 69 namespace DropPermissionForMediaFileSystem = |
(...skipping 11 matching lines...) Expand all Loading... | |
76 const char kNonExistentGalleryId[] = "Non-existent gallery id."; | 81 const char kNonExistentGalleryId[] = "Non-existent gallery id."; |
77 const char kNoScanPermission[] = "No permission to scan."; | 82 const char kNoScanPermission[] = "No permission to scan."; |
78 | 83 |
79 const char kDeviceIdKey[] = "deviceId"; | 84 const char kDeviceIdKey[] = "deviceId"; |
80 const char kGalleryIdKey[] = "galleryId"; | 85 const char kGalleryIdKey[] = "galleryId"; |
81 const char kIsAvailableKey[] = "isAvailable"; | 86 const char kIsAvailableKey[] = "isAvailable"; |
82 const char kIsMediaDeviceKey[] = "isMediaDevice"; | 87 const char kIsMediaDeviceKey[] = "isMediaDevice"; |
83 const char kIsRemovableKey[] = "isRemovable"; | 88 const char kIsRemovableKey[] = "isRemovable"; |
84 const char kNameKey[] = "name"; | 89 const char kNameKey[] = "name"; |
85 | 90 |
91 const char kMetadataKey[] = "metadata"; | |
92 const char kAttachedImagesBlobInfoKey[] = "attachedImagesBlobInfo"; | |
93 const char kBlobUUIDKey[] = "blobUUID"; | |
94 const char kTypeKey[] = "type"; | |
95 const char kSizeKey[] = "size"; | |
96 | |
86 MediaFileSystemRegistry* media_file_system_registry() { | 97 MediaFileSystemRegistry* media_file_system_registry() { |
87 return g_browser_process->media_file_system_registry(); | 98 return g_browser_process->media_file_system_registry(); |
88 } | 99 } |
89 | 100 |
90 MediaScanManager* media_scan_manager() { | 101 MediaScanManager* media_scan_manager() { |
91 return media_file_system_registry()->media_scan_manager(); | 102 return media_file_system_registry()->media_scan_manager(); |
92 } | 103 } |
93 | 104 |
94 // Checks whether the MediaGalleries API is currently accessible (it may be | 105 // Checks whether the MediaGalleries API is currently accessible (it may be |
95 // disallowed even if an extension has the requisite permission). Then | 106 // disallowed even if an extension has the requisite permission). Then |
(...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
818 if (!args_->Get(1, &options_value)) | 829 if (!args_->Get(1, &options_value)) |
819 return false; | 830 return false; |
820 scoped_ptr<MediaGalleries::MediaMetadataOptions> options = | 831 scoped_ptr<MediaGalleries::MediaMetadataOptions> options = |
821 MediaGalleries::MediaMetadataOptions::FromValue(*options_value); | 832 MediaGalleries::MediaMetadataOptions::FromValue(*options_value); |
822 if (!options) | 833 if (!options) |
823 return false; | 834 return false; |
824 | 835 |
825 bool mime_type_only = options->metadata_type == | 836 bool mime_type_only = options->metadata_type == |
826 MediaGalleries::GET_METADATA_TYPE_MIMETYPEONLY; | 837 MediaGalleries::GET_METADATA_TYPE_MIMETYPEONLY; |
827 | 838 |
839 // Get attached images by default. | |
840 bool get_attached_images = | |
841 options->metadata_type == MediaGalleries::GET_METADATA_TYPE_ALL || | |
842 options->metadata_type == MediaGalleries::GET_METADATA_TYPE_NONE; | |
843 | |
828 return Setup(GetProfile(), &error_, base::Bind( | 844 return Setup(GetProfile(), &error_, base::Bind( |
829 &MediaGalleriesGetMetadataFunction::OnPreferencesInit, this, | 845 &MediaGalleriesGetMetadataFunction::OnPreferencesInit, this, |
830 mime_type_only, blob_uuid)); | 846 mime_type_only, get_attached_images, blob_uuid)); |
831 } | 847 } |
832 | 848 |
833 void MediaGalleriesGetMetadataFunction::OnPreferencesInit( | 849 void MediaGalleriesGetMetadataFunction::OnPreferencesInit( |
834 bool mime_type_only, const std::string& blob_uuid) { | 850 bool mime_type_only, bool get_attached_images, |
851 const std::string& blob_uuid) { | |
835 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 852 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
836 | 853 |
837 // BlobReader is self-deleting. | 854 // BlobReader is self-deleting. |
838 BlobReader* reader = new BlobReader( | 855 BlobReader* reader = new BlobReader( |
839 GetProfile(), | 856 GetProfile(), |
840 blob_uuid, | 857 blob_uuid, |
841 base::Bind(&MediaGalleriesGetMetadataFunction::SniffMimeType, this, | 858 base::Bind(&MediaGalleriesGetMetadataFunction::GetMetadata, this, |
842 mime_type_only, blob_uuid)); | 859 mime_type_only, get_attached_images, blob_uuid)); |
843 reader->SetByteRange(0, net::kMaxBytesToSniff); | 860 reader->SetByteRange(0, net::kMaxBytesToSniff); |
844 reader->Start(); | 861 reader->Start(); |
845 } | 862 } |
846 | 863 |
847 void MediaGalleriesGetMetadataFunction::SniffMimeType( | 864 void MediaGalleriesGetMetadataFunction::GetMetadata( |
848 bool mime_type_only, const std::string& blob_uuid, | 865 bool mime_type_only, bool get_attached_images, |
849 scoped_ptr<std::string> blob_header, int64 total_blob_length) { | 866 const std::string& blob_uuid, scoped_ptr<std::string> blob_header, |
867 int64 total_blob_length) { | |
850 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 868 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
851 | 869 |
852 std::string mime_type; | 870 std::string mime_type; |
853 bool mime_type_sniffed = net::SniffMimeTypeFromLocalData( | 871 bool mime_type_sniffed = net::SniffMimeTypeFromLocalData( |
854 blob_header->c_str(), blob_header->size(), &mime_type); | 872 blob_header->c_str(), blob_header->size(), &mime_type); |
855 | 873 |
856 if (!mime_type_sniffed) { | 874 if (!mime_type_sniffed) { |
857 SendResponse(false); | 875 SendResponse(false); |
858 return; | 876 return; |
859 } | 877 } |
860 | 878 |
861 if (mime_type_only) { | 879 if (mime_type_only) { |
862 MediaGalleries::MediaMetadata metadata; | 880 MediaGalleries::MediaMetadata metadata; |
863 metadata.mime_type = mime_type; | 881 metadata.mime_type = mime_type; |
864 SetResult(metadata.ToValue().release()); | 882 |
883 base::DictionaryValue* result_dictionary = new base::DictionaryValue; | |
884 result_dictionary->Set(kMetadataKey, metadata.ToValue().release()); | |
885 SetResult(result_dictionary); | |
865 SendResponse(true); | 886 SendResponse(true); |
866 return; | 887 return; |
867 } | 888 } |
868 | 889 |
869 scoped_refptr<metadata::SafeMediaMetadataParser> parser( | 890 scoped_refptr<metadata::SafeMediaMetadataParser> parser( |
870 new metadata::SafeMediaMetadataParser(GetProfile(), blob_uuid, | 891 new metadata::SafeMediaMetadataParser(GetProfile(), blob_uuid, |
871 total_blob_length, mime_type)); | 892 total_blob_length, mime_type, |
893 get_attached_images)); | |
872 parser->Start(base::Bind( | 894 parser->Start(base::Bind( |
873 &MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone, this)); | 895 &MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone, this)); |
874 } | 896 } |
875 | 897 |
876 void MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone( | 898 void MediaGalleriesGetMetadataFunction::OnSafeMediaMetadataParserDone( |
877 bool parse_success, base::DictionaryValue* metadata_dictionary) { | 899 bool parse_success, scoped_ptr<base::DictionaryValue> metadata_dictionary, |
900 scoped_ptr<std::vector<metadata::AttachedImage>> attached_images) { | |
901 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
902 | |
878 if (!parse_success) { | 903 if (!parse_success) { |
879 SendResponse(false); | 904 SendResponse(false); |
880 return; | 905 return; |
881 } | 906 } |
882 | 907 |
883 SetResult(metadata_dictionary->DeepCopy()); | 908 DCHECK(attached_images.get()); |
909 if (attached_images->empty()) { | |
910 base::DictionaryValue* result_dictionary = new base::DictionaryValue; | |
911 result_dictionary->Set(kMetadataKey, metadata_dictionary.release()); | |
912 SetResult(result_dictionary); | |
913 SendResponse(true); | |
914 return; | |
915 } | |
916 | |
917 metadata::AttachedImage* first_image = &attached_images->front(); | |
918 content::BrowserContext::GetBlobContext(GetProfile())->CreateMemoryBackedBlob( | |
919 first_image->data.c_str(), | |
920 first_image->data.size(), | |
921 base::Bind(&MediaGalleriesGetMetadataFunction::ConstructNextBlob, | |
922 this, base::Passed(&metadata_dictionary), | |
923 base::Passed(&attached_images), | |
924 base::Passed(make_scoped_ptr(new std::vector<std::string>)))); | |
925 } | |
926 | |
927 void MediaGalleriesGetMetadataFunction::ConstructNextBlob( | |
928 scoped_ptr<base::DictionaryValue> metadata_dictionary, | |
929 scoped_ptr<std::vector<metadata::AttachedImage>> attached_images, | |
930 scoped_ptr<std::vector<std::string>> blob_uuids, | |
931 scoped_ptr<webkit_blob::BlobDataHandle> next_blob) { | |
932 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
933 | |
934 DCHECK(metadata_dictionary.get()); | |
935 DCHECK(attached_images.get()); | |
936 DCHECK(blob_uuids.get()); | |
937 DCHECK(next_blob.get()); | |
938 | |
939 DCHECK(!attached_images->empty()); | |
940 DCHECK_LT(blob_uuids->size(), attached_images->size()); | |
941 | |
942 // For the newly constructed blob, add its UUID to list and store reference. | |
943 blob_uuids->push_back(next_blob->uuid()); | |
944 WebContents* contents = WebContents::FromRenderViewHost(render_view_host()); | |
945 extensions::BlobHolder::CreateForWebContents(contents); | |
michaeln
2014/05/08 21:22:24
If the holder already exists, is CreateForWebConte
tommycli
2014/05/08 22:57:12
Correct. It does nothing if it already exists.
| |
946 extensions::BlobHolder* holder = | |
947 extensions::BlobHolder::FromWebContents(contents); | |
948 holder->HoldBlobReference(next_blob.Pass()); | |
949 | |
950 if (blob_uuids->size() == attached_images->size()) { | |
951 FinishRequest(metadata_dictionary.Pass(), attached_images.Pass(), | |
952 blob_uuids.Pass()); | |
953 return; | |
954 } | |
955 | |
956 // Construct the next Blob. | |
957 content::BlobContext* blob_context = | |
958 content::BrowserContext::GetBlobContext(GetProfile()); | |
959 metadata::AttachedImage* next_image = &(*attached_images)[blob_uuids->size()]; | |
960 blob_context->CreateMemoryBackedBlob( | |
961 next_image->data.c_str(), next_image->data.size(), | |
962 base::Bind(&MediaGalleriesGetMetadataFunction::ConstructNextBlob, | |
963 this, base::Passed(&metadata_dictionary), | |
964 base::Passed(&attached_images), base::Passed(&blob_uuids))); | |
965 } | |
966 | |
967 void MediaGalleriesGetMetadataFunction::FinishRequest( | |
968 scoped_ptr<base::DictionaryValue> metadata_dictionary, | |
969 scoped_ptr<std::vector<metadata::AttachedImage>> attached_images, | |
970 scoped_ptr<std::vector<std::string>> blob_uuids) { | |
971 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
972 DCHECK(metadata_dictionary.get()); | |
973 DCHECK(attached_images->size() == blob_uuids->size()); | |
974 | |
975 base::DictionaryValue* result_dictionary = new base::DictionaryValue; | |
976 result_dictionary->Set(kMetadataKey, metadata_dictionary->DeepCopy()); | |
977 | |
978 // The custom JS binding takes ownership of the Blobs in the renderer. | |
979 base::ListValue* attached_images_list = new base::ListValue; | |
980 for (size_t i = 0; i < attached_images->size(); ++i) { | |
981 base::DictionaryValue* attached_image = new base::DictionaryValue; | |
982 attached_image->Set(kBlobUUIDKey, new base::StringValue((*blob_uuids)[i])); | |
983 attached_image->Set(kTypeKey, new base::StringValue( | |
984 (*attached_images)[i].type)); | |
985 attached_image->Set(kSizeKey, new base::FundamentalValue( | |
986 base::checked_cast<int>((*attached_images)[i].data.size()))); | |
987 attached_images_list->Append(attached_image); | |
988 } | |
989 result_dictionary->Set(kAttachedImagesBlobInfoKey, attached_images_list); | |
990 | |
991 SetResult(result_dictionary); | |
884 SendResponse(true); | 992 SendResponse(true); |
michaeln
2014/05/08 21:22:24
What happens if the page which has invoked this me
tommycli
2014/05/08 22:57:12
That's a good question. The current design of Blob
| |
885 } | 993 } |
886 | 994 |
887 } // namespace extensions | 995 } // namespace extensions |
OLD | NEW |