| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 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 "platform/blob/BlobBytesProvider.h" |
| 6 |
| 7 #include "platform/wtf/Functional.h" |
| 8 #include "public/platform/Platform.h" |
| 9 |
| 10 namespace blink { |
| 11 |
| 12 namespace { |
| 13 |
| 14 class BlobBytesStreamer { |
| 15 public: |
| 16 BlobBytesStreamer(Vector<RefPtr<RawData>> data, |
| 17 mojo::ScopedDataPipeProducerHandle pipe) |
| 18 : data_(std::move(data)), |
| 19 pipe_(std::move(pipe)), |
| 20 watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC) { |
| 21 watcher_.Watch(pipe_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, |
| 22 ConvertToBaseCallback(WTF::Bind( |
| 23 &BlobBytesStreamer::OnWritable, WTF::Unretained(this)))); |
| 24 } |
| 25 |
| 26 void OnWritable(MojoResult result) { |
| 27 if (result == MOJO_RESULT_CANCELLED || |
| 28 result == MOJO_RESULT_FAILED_PRECONDITION) { |
| 29 LOG(INFO) << "Deleting, current item: " << current_item_ |
| 30 << ", current pos: " << current_item_offset_; |
| 31 delete this; |
| 32 return; |
| 33 } |
| 34 DCHECK_EQ(result, MOJO_RESULT_OK); |
| 35 |
| 36 while (true) { |
| 37 uint32_t num_bytes = |
| 38 data_[current_item_]->length() - current_item_offset_; |
| 39 MojoResult write_result = mojo::WriteDataRaw( |
| 40 pipe_.get(), data_[current_item_]->data() + current_item_offset_, |
| 41 &num_bytes, MOJO_WRITE_DATA_FLAG_NONE); |
| 42 if (write_result == MOJO_RESULT_OK) { |
| 43 LOG(INFO) << "Wrote " << num_bytes; |
| 44 current_item_offset_ += num_bytes; |
| 45 if (current_item_offset_ >= data_[current_item_]->length()) { |
| 46 current_item_++; |
| 47 if (current_item_ >= int(data_.size())) { |
| 48 // Send all items completely, done. |
| 49 LOG(INFO) << "Done writing, deleting self"; |
| 50 delete this; |
| 51 return; |
| 52 } |
| 53 } |
| 54 } else if (write_result == MOJO_RESULT_SHOULD_WAIT) { |
| 55 break; |
| 56 } else { |
| 57 // Something went wrong. |
| 58 delete this; |
| 59 return; |
| 60 } |
| 61 } |
| 62 } |
| 63 |
| 64 private: |
| 65 int current_item_ = 0; |
| 66 size_t current_item_offset_ = 0; |
| 67 Vector<RefPtr<RawData>> data_; |
| 68 |
| 69 mojo::ScopedDataPipeProducerHandle pipe_; |
| 70 mojo::SimpleWatcher watcher_; |
| 71 }; |
| 72 |
| 73 Time TimeFromDouble(double dt) { |
| 74 if (dt == 0 || std::isnan(dt)) |
| 75 return Time(); |
| 76 return Time::FromSeconds(base::Time::kTimeTToMicrosecondsOffset / 1000000 + |
| 77 dt); |
| 78 } |
| 79 |
| 80 } // namespace |
| 81 |
| 82 BlobBytesProvider::BlobBytesProvider(RefPtr<RawData> data) { |
| 83 Platform::Current()->IncProcessRefCount(); |
| 84 data_.push_back(std::move(data)); |
| 85 } |
| 86 |
| 87 BlobBytesProvider::~BlobBytesProvider() { |
| 88 Platform::Current()->DecProcessRefCount(); |
| 89 LOG(INFO) << "Destroying bytes provider for " << uuid; |
| 90 } |
| 91 |
| 92 void BlobBytesProvider::AppendData(RefPtr<RawData> data) { |
| 93 data_.push_back(std::move(data)); |
| 94 } |
| 95 |
| 96 void BlobBytesProvider::RequestAsStream( |
| 97 mojo::ScopedDataPipeProducerHandle pipe) { |
| 98 LOG(INFO) << "Data being requested as stream for " << uuid; |
| 99 // Will self delete when done. |
| 100 new BlobBytesStreamer(data_, std::move(pipe)); |
| 101 } |
| 102 |
| 103 void BlobBytesProvider::RequestAsFile(uint64_t source_offset, |
| 104 uint64_t source_size, |
| 105 base::File file, |
| 106 uint64_t file_offset, |
| 107 RequestAsFileCallback callback) { |
| 108 LOG(INFO) << "Data being requested as files" << uuid; |
| 109 // TODO(mek): Do on correct thread |
| 110 if (!file.IsValid()) { |
| 111 std::move(callback).Run(WTF::nullopt); |
| 112 return; |
| 113 } |
| 114 |
| 115 int64_t seek_distance = |
| 116 file.Seek(base::File::FROM_BEGIN, SafeCast<int64_t>(file_offset)); |
| 117 bool seek_failed = seek_distance < 0; |
| 118 // histogram Storage.Blob.RendererFileSeekFailed |
| 119 if (seek_failed) { |
| 120 std::move(callback).Run(WTF::nullopt); |
| 121 return; |
| 122 } |
| 123 |
| 124 // TODO(mek): More efficient way to find beginning. |
| 125 uint64_t offset = 0; |
| 126 for (const RefPtr<RawData>& data : data_) { |
| 127 if (offset + data->length() > source_offset) { |
| 128 uint64_t data_offset = source_offset - offset; |
| 129 uint64_t data_size = std::min(data->length() - data_offset, |
| 130 source_size - offset - source_offset); |
| 131 size_t written = 0; |
| 132 while (written < data_size) { |
| 133 size_t writing_size = data_size - written; |
| 134 int actual_written = |
| 135 file.WriteAtCurrentPos(data->data() + data_offset + written, |
| 136 static_cast<int>(writing_size)); |
| 137 bool write_failed = actual_written < 0; |
| 138 // histogram Storage.Blob.RendererFileWriteFailed |
| 139 if (write_failed) { |
| 140 std::move(callback).Run(WTF::nullopt); |
| 141 return; |
| 142 } |
| 143 written += actual_written; |
| 144 } |
| 145 } |
| 146 offset += data->length(); |
| 147 } |
| 148 |
| 149 if (!file.Flush()) { |
| 150 std::move(callback).Run(WTF::nullopt); |
| 151 return; |
| 152 } |
| 153 base::File::Info info; |
| 154 if (!file.GetInfo(&info)) { |
| 155 std::move(callback).Run(WTF::nullopt); |
| 156 return; |
| 157 } |
| 158 LOG(INFO) << "About to call final callback " << info.last_modified; |
| 159 std::move(callback).Run(TimeFromDouble(info.last_modified.ToDoubleT())); |
| 160 } |
| 161 |
| 162 } // namespace blink |
| OLD | NEW |