1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/webshare/win/share_operation.h"
6 
7 #include "base/bind.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/task/post_task.h"
10 #include "base/win/core_winrt_util.h"
11 #include "base/win/post_async_results.h"
12 #include "base/win/scoped_hstring.h"
13 #include "base/win/vector.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/webshare/share_service_impl.h"
16 #include "chrome/browser/webshare/win/show_share_ui_for_window_operation.h"
17 #include "content/public/browser/browser_task_traits.h"
18 #include "content/public/browser/web_contents.h"
19 #include "net/base/net_errors.h"
20 #include "storage/browser/blob/blob_data_handle.h"
21 #include "storage/browser/blob/blob_storage_context.h"
22 #include "storage/browser/file_system/file_stream_writer.h"
23 #include "storage/browser/file_system/file_writer_delegate.h"
24 #include "storage/common/file_system/file_system_mount_option.h"
25 #include "ui/views/win/hwnd_util.h"
26 #include "url/gurl.h"
27 
28 #include <shlobj.h>
29 #include <windows.applicationmodel.datatransfer.h>
30 #include <windows.foundation.collections.h>
31 #include <windows.foundation.h>
32 #include <windows.storage.h>
33 #include <windows.storage.streams.h>
34 #include <wininet.h>
35 #include <wrl/client.h>
36 #include <wrl/event.h>
37 
38 using ABI::Windows::ApplicationModel::DataTransfer::IDataPackage;
39 using ABI::Windows::ApplicationModel::DataTransfer::IDataPackagePropertySet;
40 using ABI::Windows::ApplicationModel::DataTransfer::IDataRequest;
41 using ABI::Windows::ApplicationModel::DataTransfer::IDataRequestDeferral;
42 using ABI::Windows::ApplicationModel::DataTransfer::IDataRequestedEventArgs;
43 using ABI::Windows::Foundation::AsyncStatus;
44 using ABI::Windows::Foundation::IAsyncOperation;
45 using ABI::Windows::Foundation::IAsyncOperationCompletedHandler;
46 using ABI::Windows::Foundation::IClosable;
47 using ABI::Windows::Foundation::IUriRuntimeClass;
48 using ABI::Windows::Foundation::IUriRuntimeClassFactory;
49 using ABI::Windows::Storage::IStorageFile;
50 using ABI::Windows::Storage::IStorageFileStatics;
51 using ABI::Windows::Storage::IStorageItem;
52 using ABI::Windows::Storage::IStreamedFileDataRequestedHandler;
53 using ABI::Windows::Storage::StorageFile;
54 using ABI::Windows::Storage::Streams::IDataWriter;
55 using ABI::Windows::Storage::Streams::IDataWriterFactory;
56 using ABI::Windows::Storage::Streams::IOutputStream;
57 using Microsoft::WRL::Callback;
58 using Microsoft::WRL::ComPtr;
59 using Microsoft::WRL::Make;
60 
61 namespace ABI {
62 namespace Windows {
63 namespace Foundation {
64 namespace Collections {
65 
66 // Define template specializations for the types used. These uuids were randomly
67 // generated.
68 template <>
69 struct __declspec(uuid("CBE31E85-DEC8-4227-987F-9C63D6AA1A2E"))
70     IObservableVector<IStorageItem*> : IObservableVector_impl<IStorageItem*> {};
71 
72 template <>
73 struct __declspec(uuid("30BE4864-5EE5-4111-916E-15126649F3C9"))
74     VectorChangedEventHandler<IStorageItem*>
75     : VectorChangedEventHandler_impl<IStorageItem*> {};
76 
77 }  // namespace Collections
78 }  // namespace Foundation
79 }  // namespace Windows
80 }  // namespace ABI
81 
82 namespace webshare {
83 namespace {
84 
85 uint64_t g_max_file_bytes = kMaxSharedFileBytes;
86 decltype(
87     &base::win::RoGetActivationFactory) g_ro_get_activation_factory_function =
88     &base::win::RoGetActivationFactory;
89 
90 template <typename InterfaceType, wchar_t const* runtime_class_id>
GetActivationFactory(InterfaceType ** factory)91 HRESULT GetActivationFactory(InterfaceType** factory) {
92   auto class_id_hstring = base::win::ScopedHString::Create(runtime_class_id);
93   if (!class_id_hstring.is_valid())
94     return E_FAIL;
95 
96   return g_ro_get_activation_factory_function(class_id_hstring.get(),
97                                               IID_PPV_ARGS(factory));
98 }
99 
100 // Implements FileStreamWriter for an IDataWriter.
101 class DataWriterFileStreamWriter final : public storage::FileStreamWriter {
102  public:
DataWriterFileStreamWriter(ComPtr<IDataWriter> data_writer,scoped_refptr<base::RefCountedData<uint64_t>> file_bytes_shared)103   explicit DataWriterFileStreamWriter(
104       ComPtr<IDataWriter> data_writer,
105       scoped_refptr<base::RefCountedData<uint64_t>> file_bytes_shared)
106       : data_writer_(data_writer), file_bytes_shared_(file_bytes_shared) {}
107 
Cancel(net::CompletionOnceCallback callback)108   int Cancel(net::CompletionOnceCallback callback) final {
109     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
110     // If there is no async operation in progress, Cancel() should
111     // return net::ERR_UNEXPECTED per file_stream_header.h
112     if (!flush_operation_ && !write_operation_)
113       return net::ERR_UNEXPECTED;
114 
115     if (flush_operation_) {
116       flush_callback_.Reset();
117       ComPtr<IAsyncInfo> async_info;
118       auto hr = flush_operation_.As(&async_info);
119       if (FAILED(hr))
120         return net::ERR_UNEXPECTED;
121 
122       hr = async_info->Cancel();
123       if (FAILED(hr))
124         return net::ERR_UNEXPECTED;
125 
126       flush_operation_.Reset();
127     }
128 
129     if (write_operation_) {
130       write_callback_.Reset();
131       ComPtr<IAsyncInfo> async_info;
132       auto hr = write_operation_.As(&async_info);
133       if (FAILED(hr))
134         return net::ERR_UNEXPECTED;
135 
136       hr = async_info->Cancel();
137       if (FAILED(hr))
138         return net::ERR_UNEXPECTED;
139 
140       write_operation_.Reset();
141     }
142     return net::OK;
143   }
144 
Flush(net::CompletionOnceCallback callback)145   int Flush(net::CompletionOnceCallback callback) final {
146     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
147     DCHECK(flush_callback_.is_null());
148     DCHECK_EQ(flush_operation_, nullptr);
149     DCHECK(write_callback_.is_null());
150     DCHECK_EQ(write_operation_, nullptr);
151 
152     auto hr = data_writer_->FlushAsync(&flush_operation_);
153     if (FAILED(hr))
154       return net::ERR_UNEXPECTED;
155 
156     flush_callback_ = std::move(callback);
157     base::win::PostAsyncResults(
158         flush_operation_,
159         base::BindOnce(&DataWriterFileStreamWriter::OnFlushCompleted,
160                        weak_factory_.GetWeakPtr()));
161     return net::ERR_IO_PENDING;
162   }
163 
Write(net::IOBuffer * buf,int buf_len,net::CompletionOnceCallback callback)164   int Write(net::IOBuffer* buf,
165             int buf_len,
166             net::CompletionOnceCallback callback) final {
167     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
168     DCHECK(flush_callback_.is_null());
169     DCHECK_EQ(flush_operation_, nullptr);
170     DCHECK(write_callback_.is_null());
171     DCHECK_EQ(write_operation_, nullptr);
172 
173     // Before processing the Write request, increment the total number of file
174     // bytes shared as part of the overall Share operation this belongs to, and
175     // if it has exceeded the maximum allowed, abort writing to the streamed
176     // file.
177     file_bytes_shared_->data += buf_len;
178     if (file_bytes_shared_->data > g_max_file_bytes)
179       return net::ERR_UNEXPECTED;
180 
181     auto hr =
182         data_writer_->WriteBytes(buf_len, reinterpret_cast<BYTE*>(buf->data()));
183     if (FAILED(hr))
184       return net::ERR_UNEXPECTED;
185 
186     hr = data_writer_->StoreAsync(&write_operation_);
187     if (FAILED(hr))
188       return net::ERR_UNEXPECTED;
189 
190     write_callback_ = std::move(callback);
191     base::win::PostAsyncResults(
192         write_operation_,
193         base::BindOnce(&DataWriterFileStreamWriter::OnWriteCompleted,
194                        weak_factory_.GetWeakPtr()));
195     return net::ERR_IO_PENDING;
196   }
197 
198  private:
OnFlushCompleted(boolean operation_result)199   void OnFlushCompleted(boolean operation_result) {
200     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
201     DCHECK(!flush_callback_.is_null());
202     DCHECK_NE(flush_operation_, nullptr);
203     DCHECK(write_callback_.is_null());
204     DCHECK_EQ(write_operation_, nullptr);
205 
206     flush_operation_.Reset();
207     int result = operation_result == TRUE ? net::OK : net::ERR_UNEXPECTED;
208     std::move(flush_callback_).Run(result);
209   }
210 
OnWriteCompleted(UINT32 operation_result)211   void OnWriteCompleted(UINT32 operation_result) {
212     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
213     DCHECK(flush_callback_.is_null());
214     DCHECK_EQ(flush_operation_, nullptr);
215     DCHECK(!write_callback_.is_null());
216     DCHECK_NE(write_operation_, nullptr);
217 
218     write_operation_.Reset();
219     std::move(write_callback_).Run(operation_result);
220   }
221 
222   ComPtr<IDataWriter> data_writer_;
223   scoped_refptr<base::RefCountedData<uint64_t>> file_bytes_shared_;
224   net::CompletionOnceCallback flush_callback_;
225   ComPtr<IAsyncOperation<bool>> flush_operation_;
226   net::CompletionOnceCallback write_callback_;
227   ComPtr<IAsyncOperation<UINT32>> write_operation_;
228   base::WeakPtrFactory<DataWriterFileStreamWriter> weak_factory_{this};
229 };
230 
231 // Represents an ongoing operation of writing to an IOutputStream.
232 class OutputStreamWriteOperation
233     : public base::RefCounted<OutputStreamWriteOperation> {
234  public:
OutputStreamWriteOperation(content::BrowserContext::BlobContextGetter blob_context_getter,scoped_refptr<base::RefCountedData<uint64_t>> file_bytes_shared,std::string uuid)235   OutputStreamWriteOperation(
236       content::BrowserContext::BlobContextGetter blob_context_getter,
237       scoped_refptr<base::RefCountedData<uint64_t>> file_bytes_shared,
238       std::string uuid)
239       : blob_context_getter_(blob_context_getter),
240         file_bytes_shared_(file_bytes_shared),
241         uuid_(uuid) {}
242 
243   // Begins the write operation on the |stream|, maintaining a reference to the
244   // |stream| until the operation is completed, at which point it will be closed
245   // (if possible) and the |on_complete| callback will be invoked. The caller
246   // is still responsible for the lifetime of this object, but not of the
247   // |stream|.
WriteStream(IOutputStream * stream,base::OnceCallback<void ()> on_complete)248   void WriteStream(IOutputStream* stream,
249                    base::OnceCallback<void()> on_complete) {
250     stream_ = ComPtr<IOutputStream>(stream);
251     on_complete_ = std::move(on_complete);
252     if (!base::PostTask(
253             FROM_HERE, {content::BrowserThread::IO},
254             base::BindOnce(&OutputStreamWriteOperation::WriteStreamOnIOThread,
255                            weak_factory_.GetWeakPtr())))
256       Complete();
257   }
258 
259  private:
260   friend class base::RefCounted<OutputStreamWriteOperation>;
261 
262   ~OutputStreamWriteOperation() = default;
263 
WriteStreamOnIOThread()264   void WriteStreamOnIOThread() {
265     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
266 
267     storage::BlobStorageContext* blob_storage_context =
268         blob_context_getter_.Run().get();
269     if (!blob_storage_context) {
270       Complete();
271       return;
272     }
273 
274     blob_handle_ = blob_storage_context->GetBlobDataFromUUID(uuid_);
275 
276     ComPtr<IDataWriterFactory> data_writer_factory;
277     auto hr =
278         GetActivationFactory<IDataWriterFactory,
279                              RuntimeClass_Windows_Storage_Streams_DataWriter>(
280             &data_writer_factory);
281     if (FAILED(hr)) {
282       Complete();
283       return;
284     }
285 
286     ComPtr<IDataWriter> data_writer;
287     hr = data_writer_factory->CreateDataWriter(stream_.Get(), &data_writer);
288     if (FAILED(hr)) {
289       Complete();
290       return;
291     }
292 
293     writer_delegate_ = std::make_unique<storage::FileWriterDelegate>(
294         std::make_unique<DataWriterFileStreamWriter>(std::move(data_writer),
295                                                      file_bytes_shared_),
296         storage::FlushPolicy::FLUSH_ON_COMPLETION);
297     writer_delegate_->Start(
298         blob_handle_->CreateReader(),
299         base::BindRepeating(&OutputStreamWriteOperation::OnFileWritten,
300                             weak_factory_.GetWeakPtr()));
301   }
302 
OnFileWritten(base::File::Error error,int64_t bytes_wrriten,storage::FileWriterDelegate::WriteProgressStatus write_status)303   void OnFileWritten(
304       base::File::Error error,
305       int64_t bytes_wrriten,
306       storage::FileWriterDelegate::WriteProgressStatus write_status) {
307     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
308     // Any status other than SUCCESS_IO_PENDING indicates completion.
309     if (write_status !=
310         storage::FileWriterDelegate::WriteProgressStatus::SUCCESS_IO_PENDING) {
311       Complete();
312     }
313   }
314 
Complete()315   void Complete() {
316     // If the IOutputStream implements IClosable (e.g. the OutputStream class),
317     // close the stream whenever we are done with this operation, regardless of
318     // the outcome.
319     if (stream_) {
320       ComPtr<IClosable> closable;
321       if (SUCCEEDED(stream_.As(&closable)))
322         closable->Close();
323     }
324 
325     std::move(on_complete_).Run();
326   }
327 
328   content::BrowserContext::BlobContextGetter blob_context_getter_;
329   std::unique_ptr<storage::BlobDataHandle> blob_handle_;
330   scoped_refptr<base::RefCountedData<uint64_t>> file_bytes_shared_;
331   base::OnceCallback<void()> on_complete_;
332   ComPtr<IOutputStream> stream_;
333   const std::string uuid_;
334   std::unique_ptr<storage::FileWriterDelegate> writer_delegate_;
335   base::WeakPtrFactory<OutputStreamWriteOperation> weak_factory_{this};
336 };
337 }  // namespace
338 
339 // static
SetMaxFileBytesForTesting(uint64_t max_file_bytes)340 void ShareOperation::SetMaxFileBytesForTesting(uint64_t max_file_bytes) {
341   g_max_file_bytes = max_file_bytes;
342 }
343 
344 // static
SetRoGetActivationFactoryFunctionForTesting(decltype(& base::win::RoGetActivationFactory)value)345 void ShareOperation::SetRoGetActivationFactoryFunctionForTesting(
346     decltype(&base::win::RoGetActivationFactory) value) {
347   g_ro_get_activation_factory_function = value;
348 }
349 
ShareOperation(const std::string & title,const std::string & text,const GURL & url,std::vector<blink::mojom::SharedFilePtr> files,content::WebContents * web_contents)350 ShareOperation::ShareOperation(const std::string& title,
351                                const std::string& text,
352                                const GURL& url,
353                                std::vector<blink::mojom::SharedFilePtr> files,
354                                content::WebContents* web_contents)
355     : content::WebContentsObserver(web_contents),
356       title_(std::move(title)),
357       text_(std::move(text)),
358       url_(std::move(url)),
359       files_(std::move(files)) {}
360 
~ShareOperation()361 ShareOperation::~ShareOperation() {
362   if (callback_)
363     Complete(blink::mojom::ShareError::CANCELED);
364 }
365 
AsWeakPtr()366 base::WeakPtr<ShareOperation> ShareOperation::AsWeakPtr() {
367   return weak_factory_.GetWeakPtr();
368 }
369 
Run(blink::mojom::ShareService::ShareCallback callback)370 void ShareOperation::Run(blink::mojom::ShareService::ShareCallback callback) {
371   DCHECK(!callback_);
372   callback_ = std::move(callback);
373 
374   // If the required WinRT functionality is not available, or the corresponding
375   // web_contents have already been cleaned up, cancel the operation
376   const bool winrt_environment_ok =
377       base::win::ResolveCoreWinRTDelayload() &&
378       base::win::ScopedHString::ResolveCoreWinRTStringDelayload();
379   if (!winrt_environment_ok || !web_contents()) {
380     Complete(blink::mojom::ShareError::CANCELED);
381     return;
382   }
383 
384   if (files_.size() > 0) {
385     // Determine the source for use with the OS IAttachmentExecute.
386     // If the source cannot be determined, does not appear to be valid,
387     // or is longer than the max length supported by the IAttachmentExecute
388     // service, use a generic value that reliably maps to the Internet zone.
389     GURL source_url = web_contents()->GetLastCommittedURL();
390     base::string16 source =
391         (source_url.is_valid() &&
392          source_url.spec().size() <= INTERNET_MAX_URL_LENGTH)
393             ? base::UTF8ToUTF16(source_url.spec())
394             : L"about:internet";
395 
396     // For each "file", check against the OS that it is allowed
397     // The same instance cannot be used to check multiple files, so this
398     // makes a new one per-file. For more details on this functionality, see
399     // https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iattachmentexecute-checkpolicy
400     for (auto& file : files_) {
401       ComPtr<IAttachmentExecute> attachment_services;
402       if (FAILED(CoCreateInstance(CLSID_AttachmentServices, nullptr, CLSCTX_ALL,
403                                   IID_PPV_ARGS(&attachment_services)))) {
404         Complete(blink::mojom::ShareError::INTERNAL_ERROR);
405         return;
406       }
407       if (FAILED(attachment_services->SetSource(source.c_str()))) {
408         Complete(blink::mojom::ShareError::INTERNAL_ERROR);
409         return;
410       }
411       if (FAILED(attachment_services->SetFileName(
412               base::UTF8ToWide(file->name).c_str()))) {
413         Complete(blink::mojom::ShareError::INTERNAL_ERROR);
414         return;
415       }
416       if (FAILED(attachment_services->CheckPolicy())) {
417         Complete(blink::mojom::ShareError::PERMISSION_DENIED);
418         return;
419       }
420     }
421   }
422 
423   HWND hwnd =
424       views::HWNDForNativeWindow(web_contents()->GetTopLevelNativeWindow());
425   show_share_ui_for_window_operation_ =
426       std::make_unique<ShowShareUIForWindowOperation>(hwnd);
427   show_share_ui_for_window_operation_->Run(base::BindOnce(
428       &ShareOperation::OnDataRequested, weak_factory_.GetWeakPtr()));
429 }
430 
OnDataRequested(IDataRequestedEventArgs * event_args)431 void ShareOperation::OnDataRequested(IDataRequestedEventArgs* event_args) {
432   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
433 
434   blink::mojom::ShareError share_result;
435   if (!event_args || !web_contents()) {
436     share_result = blink::mojom::ShareError::CANCELED;
437   } else {
438     if (PutShareContentInEventArgs(event_args)) {
439       share_result = blink::mojom::ShareError::OK;
440     } else {
441       share_result = blink::mojom::ShareError::INTERNAL_ERROR;
442     }
443   }
444 
445   // If the share operation failed or is not being deferred, mark it as complete
446   if (share_result != blink::mojom::ShareError::OK || !data_request_deferral_)
447     Complete(share_result);
448 }
449 
PutShareContentInEventArgs(IDataRequestedEventArgs * event_args)450 bool ShareOperation::PutShareContentInEventArgs(
451     IDataRequestedEventArgs* event_args) {
452   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
453 
454   ComPtr<IDataRequest> data_request;
455   if (FAILED(event_args->get_Request(&data_request)))
456     return false;
457 
458   if (FAILED(data_request->get_Data(&data_package_)))
459     return false;
460 
461   ComPtr<IDataPackagePropertySet> data_prop_sets;
462   if (FAILED(data_package_->get_Properties(&data_prop_sets)))
463     return false;
464 
465   // Title is a required property for the UWP Share contract, so
466   // if the provided title is empty we instead use a blank value.
467   // https://docs.microsoft.com/en-us/windows/uwp/app-to-app/share-data
468   base::win::ScopedHString title_h =
469       base::win::ScopedHString::Create(title_.empty() ? " " : title_.c_str());
470   if (FAILED(data_prop_sets->put_Title(title_h.get())))
471     return false;
472 
473   return PutShareContentInDataPackage(data_request.Get());
474 }
475 
PutShareContentInDataPackage(IDataRequest * data_request)476 bool ShareOperation::PutShareContentInDataPackage(IDataRequest* data_request) {
477   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
478 
479   if (!text_.empty()) {
480     auto text_h = base::win::ScopedHString::Create(text_);
481     if (FAILED(data_package_->SetText(text_h.get())))
482       return false;
483   }
484 
485   if (!url_.spec().empty()) {
486     ComPtr<IUriRuntimeClassFactory> uri_factory;
487     auto hr =
488         GetActivationFactory<IUriRuntimeClassFactory,
489                              RuntimeClass_Windows_Foundation_Uri>(&uri_factory);
490     if (FAILED(hr))
491       return hr;
492 
493     auto url_h = base::win::ScopedHString::Create(url_.spec().c_str());
494     ComPtr<IUriRuntimeClass> uri;
495     if (FAILED(uri_factory->CreateUri(url_h.get(), &uri)))
496       return false;
497 
498     if (FAILED(data_package_->SetUri(uri.Get())))
499       return false;
500   }
501 
502   if (!files_.empty()) {
503     // Fetch a deferral to allow for async operations
504     if (FAILED(data_request->GetDeferral(&data_request_deferral_)))
505       return false;
506 
507     // Initialize the output collection for the async operation(s)
508     storage_items_ = Make<base::win::Vector<IStorageItem*>>();
509 
510     // Create a variable to be shared between all the operations processing the
511     // blobs to streams. This will be used to keep a running count of total file
512     // bytes shared as part of this Share operation so that if the maximum
513     // allowed is exceeded the processing can be halted. Currently the
514     // ShareOperation class is not guaranteed to outlive these operations, but
515     // if that changes in the future it may be appropriate to make this a member
516     // of the ShareOperation that is shared only be reference.
517     auto file_bytes_shared =
518         base::MakeRefCounted<base::RefCountedData<uint64_t>>(0);
519 
520     ComPtr<IStorageFileStatics> storage_statics;
521     auto hr = GetActivationFactory<IStorageFileStatics,
522                                    RuntimeClass_Windows_Storage_StorageFile>(
523         &storage_statics);
524     if (FAILED(hr))
525       return false;
526 
527     for (auto& file : files_) {
528       // This operation for converting the corresponding blob to a stream is
529       // maintained as a scoped_refptr because it may out live this
530       // ShareOperation instance. It is only invoked when the user has chosen a
531       // Share target and that target decides to start reading the contents of
532       // the corresponding IStorageFile. See
533       // https://docs.microsoft.com/en-us/uwp/api/windows.storage.storagefile.createstreamedfileasync
534       // If in the future the ShareOperation class is changed to live until the
535       // target app has finished fully processing the shared content this could
536       // be updated to be owned/maintained by this ShareOperation instance.
537       auto operation = base::MakeRefCounted<OutputStreamWriteOperation>(
538           content::BrowserContext::GetBlobStorageContext(
539               web_contents()->GetBrowserContext()),
540           file_bytes_shared, file->blob->uuid);
541       auto name_h = base::win::ScopedHString::Create(file->name);
542       auto raw_data_requested_callback =
543           Callback<IStreamedFileDataRequestedHandler>(
544               [operation](IOutputStream* stream) -> HRESULT {
545                 // No additional work is needed when the write has been
546                 // completed, but a callback is created to hold a reference
547                 // to the |operation| until the operation has completed.
548                 operation->WriteStream(
549                     stream,
550                     base::BindOnce(
551                         base::DoNothing::Once<
552                             scoped_refptr<OutputStreamWriteOperation>>(),
553                         operation));
554                 return S_OK;
555               });
556       // The Callback function may return null in the E_OUTOFMEMORY case
557       if (!raw_data_requested_callback)
558         return false;
559       ComPtr<IAsyncOperation<StorageFile*>> async_operation;
560       if (FAILED(storage_statics->CreateStreamedFileAsync(
561               name_h.get(), raw_data_requested_callback.Get(),
562               /*thumbnail*/ nullptr, &async_operation))) {
563         return false;
564       }
565 
566       if (FAILED(base::win::PostAsyncResults(
567               async_operation,
568               base::BindOnce(&ShareOperation::OnStreamedFileCreated,
569                              weak_factory_.GetWeakPtr()))))
570         return false;
571     }
572   }
573 
574   return true;
575 }
576 
OnStreamedFileCreated(ComPtr<IStorageFile> storage_file)577 void ShareOperation::OnStreamedFileCreated(ComPtr<IStorageFile> storage_file) {
578   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
579 
580   // If there is no callback this ShareOperation already completed due to an
581   // error, so work can be halted early.
582   if (!callback_)
583     return;
584 
585   if (!storage_file) {
586     Complete(blink::mojom::ShareError::INTERNAL_ERROR);
587     return;
588   }
589 
590   ComPtr<IStorageItem> storage_item;
591   if (FAILED(storage_file.As(&storage_item))) {
592     Complete(blink::mojom::ShareError::INTERNAL_ERROR);
593     return;
594   }
595 
596   if (FAILED(storage_items_->Append(storage_item.Get()))) {
597     Complete(blink::mojom::ShareError::INTERNAL_ERROR);
598     return;
599   }
600 
601   unsigned int size;
602   if (FAILED(storage_items_->get_Size(&size))) {
603     Complete(blink::mojom::ShareError::INTERNAL_ERROR);
604     return;
605   }
606 
607   // If this is not the final file, no more work to do
608   if (size != files_.size())
609     return;
610 
611   if (FAILED(data_package_->SetStorageItems(storage_items_.Get(),
612                                             true /*readonly*/))) {
613     Complete(blink::mojom::ShareError::INTERNAL_ERROR);
614     return;
615   }
616 
617   data_request_deferral_->Complete();
618   Complete(blink::mojom::ShareError::OK);
619   return;
620 }
621 
Complete(const blink::mojom::ShareError share_result)622 void ShareOperation::Complete(const blink::mojom::ShareError share_result) {
623   std::move(callback_).Run(share_result);
624 }
625 
626 }  // namespace webshare
627