file_select_helper.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // Copyright (c) 2021 Microsoft. All rights reserved.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #ifndef ELECTRON_SHELL_BROWSER_FILE_SELECT_HELPER_H_
  5. #define ELECTRON_SHELL_BROWSER_FILE_SELECT_HELPER_H_
  6. #include <memory>
  7. #include <string>
  8. #include <vector>
  9. #include "base/compiler_specific.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "base/scoped_observation.h"
  12. #include "build/build_config.h"
  13. #include "content/public/browser/browser_thread.h"
  14. #include "content/public/browser/render_widget_host.h"
  15. #include "content/public/browser/render_widget_host_observer.h"
  16. #include "content/public/browser/web_contents_observer.h"
  17. #include "net/base/directory_lister.h"
  18. #include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
  19. #include "ui/shell_dialogs/select_file_dialog.h"
  20. namespace content {
  21. class FileSelectListener;
  22. class WebContents;
  23. } // namespace content
  24. namespace ui {
  25. struct SelectedFileInfo;
  26. }
  27. // This class handles file-selection requests coming from renderer processes.
  28. // It implements both the initialisation and listener functions for
  29. // file-selection dialogs.
  30. //
  31. // Since FileSelectHelper listens to observations of a widget, it needs to live
  32. // on and be destroyed on the UI thread. References to FileSelectHelper may be
  33. // passed on to other threads.
  34. class FileSelectHelper : public base::RefCountedThreadSafe<
  35. FileSelectHelper,
  36. content::BrowserThread::DeleteOnUIThread>,
  37. public ui::SelectFileDialog::Listener,
  38. public content::WebContentsObserver,
  39. private net::DirectoryLister::DirectoryListerDelegate {
  40. public:
  41. // disable copy
  42. FileSelectHelper(const FileSelectHelper&) = delete;
  43. FileSelectHelper& operator=(const FileSelectHelper&) = delete;
  44. // Show the file chooser dialog.
  45. static void RunFileChooser(
  46. content::RenderFrameHost* render_frame_host,
  47. scoped_refptr<content::FileSelectListener> listener,
  48. const blink::mojom::FileChooserParams& params);
  49. // Enumerates all the files in directory.
  50. static void EnumerateDirectory(
  51. content::WebContents* tab,
  52. scoped_refptr<content::FileSelectListener> listener,
  53. const base::FilePath& path);
  54. private:
  55. friend class base::RefCountedThreadSafe<FileSelectHelper>;
  56. friend class base::DeleteHelper<FileSelectHelper>;
  57. friend struct content::BrowserThread::DeleteOnThread<
  58. content::BrowserThread::UI>;
  59. FileSelectHelper();
  60. ~FileSelectHelper() override;
  61. void RunFileChooser(content::RenderFrameHost* render_frame_host,
  62. scoped_refptr<content::FileSelectListener> listener,
  63. blink::mojom::FileChooserParamsPtr params);
  64. void GetFileTypesInThreadPool(blink::mojom::FileChooserParamsPtr params);
  65. void GetSanitizedFilenameOnUIThread(
  66. blink::mojom::FileChooserParamsPtr params);
  67. void RunFileChooserOnUIThread(const base::FilePath& default_path,
  68. blink::mojom::FileChooserParamsPtr params);
  69. // Cleans up and releases this instance. This must be called after the last
  70. // callback is received from the file chooser dialog.
  71. void RunFileChooserEnd();
  72. // SelectFileDialog::Listener overrides.
  73. void FileSelected(const ui::SelectedFileInfo& file,
  74. int index,
  75. void* params) override;
  76. void MultiFilesSelected(const std::vector<ui::SelectedFileInfo>& files,
  77. void* params) override;
  78. void FileSelectionCanceled(void* params) override;
  79. // content::WebContentsObserver overrides.
  80. void RenderFrameHostChanged(content::RenderFrameHost* old_host,
  81. content::RenderFrameHost* new_host) override;
  82. void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
  83. void WebContentsDestroyed() override;
  84. void EnumerateDirectoryImpl(
  85. content::WebContents* tab,
  86. scoped_refptr<content::FileSelectListener> listener,
  87. const base::FilePath& path);
  88. // Kicks off a new directory enumeration.
  89. void StartNewEnumeration(const base::FilePath& path);
  90. // net::DirectoryLister::DirectoryListerDelegate overrides.
  91. void OnListFile(
  92. const net::DirectoryLister::DirectoryListerData& data) override;
  93. void OnListDone(int error) override;
  94. void LaunchConfirmationDialog(
  95. const base::FilePath& path,
  96. std::vector<ui::SelectedFileInfo> selected_files);
  97. // Cleans up and releases this instance. This must be called after the last
  98. // callback is received from the enumeration code.
  99. void EnumerateDirectoryEnd();
  100. #if BUILDFLAG(IS_MAC)
  101. // Must be called from a MayBlock() task. Each selected file that is a package
  102. // will be zipped, and the zip will be passed to the render view host in place
  103. // of the package.
  104. void ProcessSelectedFilesMac(const std::vector<ui::SelectedFileInfo>& files);
  105. // Saves the paths of |zipped_files| for later deletion. Passes |files| to the
  106. // render view host.
  107. void ProcessSelectedFilesMacOnUIThread(
  108. const std::vector<ui::SelectedFileInfo>& files,
  109. const std::vector<base::FilePath>& zipped_files);
  110. // Zips the package at |path| into a temporary destination. Returns the
  111. // temporary destination, if the zip was successful. Otherwise returns an
  112. // empty path.
  113. static base::FilePath ZipPackage(const base::FilePath& path);
  114. #endif // BUILDFLAG(IS_MAC)
  115. void ConvertToFileChooserFileInfoList(
  116. const std::vector<ui::SelectedFileInfo>& files);
  117. // Checks to see if scans are required for the specified files.
  118. void PerformContentAnalysisIfNeeded(
  119. std::vector<blink::mojom::FileChooserFileInfoPtr> list);
  120. // Finish the PerformContentAnalysisIfNeeded() handling after the
  121. // deep scanning checks have been performed. Deep scanning may change the
  122. // list of files chosen by the user, so the list of files passed here may be
  123. // a subset of of the files passed to PerformContentAnalysisIfNeeded().
  124. void NotifyListenerAndEnd(
  125. std::vector<blink::mojom::FileChooserFileInfoPtr> list);
  126. // Schedules the deletion of the files in |temporary_files_| and clears the
  127. // vector.
  128. void DeleteTemporaryFiles();
  129. // Cleans up when the initiator of the file chooser is no longer valid.
  130. void CleanUp();
  131. // Calls RunFileChooserEnd() if the webcontents was destroyed. Returns true
  132. // if the file chooser operation shouldn't proceed.
  133. bool AbortIfWebContentsDestroyed();
  134. void SetFileSelectListenerForTesting(
  135. scoped_refptr<content::FileSelectListener> listener);
  136. // Helper method to get allowed extensions for select file dialog from
  137. // the specified accept types as defined in the spec:
  138. // http://whatwg.org/html/number-state.html#attr-input-accept
  139. // |accept_types| contains only valid lowercased MIME types or file extensions
  140. // beginning with a period (.).
  141. static std::unique_ptr<ui::SelectFileDialog::FileTypeInfo>
  142. GetFileTypesFromAcceptType(const std::vector<std::u16string>& accept_types);
  143. // Check the accept type is valid. It is expected to be all lower case with
  144. // no whitespace.
  145. static bool IsAcceptTypeValid(const std::string& accept_type);
  146. // Get a sanitized filename suitable for use as a default filename.
  147. static base::FilePath GetSanitizedFileName(
  148. const base::FilePath& suggested_path);
  149. // The RenderFrameHost and WebContents for the page showing a file dialog
  150. // (may only be one such dialog).
  151. raw_ptr<content::RenderFrameHost> render_frame_host_;
  152. raw_ptr<content::WebContents> web_contents_;
  153. // |listener_| receives the result of the FileSelectHelper.
  154. scoped_refptr<content::FileSelectListener> listener_;
  155. // Dialog box used for choosing files to upload from file form fields.
  156. scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
  157. std::unique_ptr<ui::SelectFileDialog::FileTypeInfo> select_file_types_;
  158. // The type of file dialog last shown. This is SELECT_NONE if an
  159. // instance is created through the public EnumerateDirectory().
  160. ui::SelectFileDialog::Type dialog_type_;
  161. // The mode of file dialog last shown.
  162. blink::mojom::FileChooserParams::Mode dialog_mode_;
  163. // The enumeration root directory for EnumerateDirectory() and
  164. // RunFileChooser with kUploadFolder.
  165. base::FilePath base_dir_;
  166. // Maintain an active directory enumeration. These could come from the file
  167. // select dialog or from drag-and-drop of directories. There could not be
  168. // more than one going on at a time.
  169. struct ActiveDirectoryEnumeration;
  170. std::unique_ptr<ActiveDirectoryEnumeration> directory_enumeration_;
  171. // Temporary files only used on OSX. This class is responsible for deleting
  172. // these files when they are no longer needed.
  173. std::vector<base::FilePath> temporary_files_;
  174. };
  175. #endif // ELECTRON_SHELL_BROWSER_FILE_SELECT_HELPER_H_