| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 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 "content/browser/loader/mojo_stream_writer.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/guid.h" |
| 9 #include "base/numerics/safe_conversions.h" |
| 10 #include "content/browser/streams/stream.h" |
| 11 #include "content/browser/streams/stream_registry.h" |
| 12 #include "content/public/browser/resource_controller.h" |
| 13 #include "net/base/io_buffer.h" |
| 14 #include "url/gurl.h" |
| 15 #include "url/url_constants.h" |
| 16 |
| 17 namespace content { |
| 18 |
| 19 MojoStreamWriter::MojoStreamWriter() |
| 20 : controller_(nullptr), buffer_(nullptr), buffer_size_(-1) {} |
| 21 |
| 22 MojoStreamWriter::~MojoStreamWriter() { |
| 23 if (data_producer_handle_.is_valid()) |
| 24 Finalize(); |
| 25 } |
| 26 |
| 27 void MojoStreamWriter::InitializeStream( |
| 28 mojo::ScopedDataPipeConsumerHandle* data_consumer_handle) { |
| 29 LOG(ERROR) << "MojoStreamWriter@" << this << " InitializeStream"; |
| 30 DCHECK(!data_producer_handle_.is_valid()); |
| 31 |
| 32 // TODO(carlosk): why not have a default constructor for this struct??? |
| 33 // The user having to default initialize it is bad. |
| 34 MojoCreateDataPipeOptions options; |
| 35 options.struct_size = sizeof(MojoCreateDataPipeOptions); |
| 36 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; |
| 37 options.element_num_bytes = 1; |
| 38 options.capacity_num_bytes = kReadBufSize; |
| 39 |
| 40 mojo::DataPipe data_pipe(options); |
| 41 data_producer_handle_ = std::move(data_pipe.producer_handle); |
| 42 *data_consumer_handle = std::move(data_pipe.consumer_handle); |
| 43 |
| 44 // TODO(carlosk): We're creating the buffer ahead of time because: |
| 45 // - I'm guessing that by using mojo::(Begin|End)WriteDataRaw we get access to |
| 46 // the final memory position that has to be written to and avoid temporary |
| 47 // copies. |
| 48 // - And because of the mismatch of the Mojo and this class' APIs in regards |
| 49 // to when the information about the need to defer further writes is available |
| 50 // from Mojo and when deferring is allowed by the calls. |
| 51 // TODO(carlosk): Should make sure MOJO_WRITE_DATA_FLAG_ALL_OR_NONE is in fact |
| 52 // needed here and in the Begin* calls below. |
| 53 // TODO(carlosk): need to properly handle Mojo error cases (MojoResult). Here |
| 54 // and everywhere else. |
| 55 buffer_size_ = kReadBufSize; |
| 56 CHECK_EQ( |
| 57 mojo::BeginWriteDataRaw(data_producer_handle_.get(), &buffer_, |
| 58 &buffer_size_, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE), |
| 59 MOJO_RESULT_OK); |
| 60 } |
| 61 |
| 62 void MojoStreamWriter::OnWillRead(scoped_refptr<net::IOBuffer>* buf, |
| 63 int* buf_size, |
| 64 int min_size) { |
| 65 LOG(ERROR) << "MojoStreamWriter@" << this << " OnWillRead"; |
| 66 |
| 67 DCHECK(buf); |
| 68 DCHECK(buf_size > 0); |
| 69 DCHECK_LE(min_size, base::checked_cast<int>(kReadBufSize)); |
| 70 // TODO(carlosk): using a net::WrappedIOBuffer might be unsafe! The buffer's |
| 71 // life cycle must be better understood and we must be certain there will not |
| 72 // be cases of user after free. |
| 73 *buf = new net::WrappedIOBuffer(static_cast<char*>(buffer_)); |
| 74 *buf_size = base::checked_cast<int>(buffer_size_); |
| 75 buffer_ = nullptr; |
| 76 buffer_size_ = -1; |
| 77 } |
| 78 |
| 79 void MojoStreamWriter::OnReadCompleted(int bytes_read, bool* defer) { |
| 80 CHECK(data_producer_handle_.is_valid()); |
| 81 LOG(ERROR) << "MojoStreamWriter@" << this |
| 82 << " OnReadCompleted: bytes_read = " << bytes_read; |
| 83 if (!bytes_read) |
| 84 return; |
| 85 |
| 86 // We have more data to read. |
| 87 // DCHECK(read_buffer_.get()); |
| 88 |
| 89 // TODO(carlosk): double check if there's need for the equivalent of |
| 90 // StreamWriter's immediate_mode for Mojo Data Pipes. |
| 91 CHECK_EQ(mojo::EndWriteDataRaw(data_producer_handle_.get(), bytes_read), |
| 92 MOJO_RESULT_OK); |
| 93 |
| 94 // TODO(carlosk): hack to comply with the "deferring" interface (further |
| 95 // explained in constructor). |
| 96 buffer_size_ = kReadBufSize; |
| 97 MojoResult result = |
| 98 mojo::BeginWriteDataRaw(data_producer_handle_.get(), &buffer_, |
| 99 &buffer_size_, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); |
| 100 |
| 101 if (result == MOJO_RESULT_SHOULD_WAIT) { |
| 102 handle_watcher_.Start(data_producer_handle_.get(), |
| 103 MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_DEADLINE_INDEFINITE, |
| 104 base::Bind(&MojoStreamWriter::OnSpaceAvailable, |
| 105 base::Unretained(this))); |
| 106 *defer = true; |
| 107 LOG(ERROR) << "MojoStreamWriter@" << this |
| 108 << " OnReadCompleted - deferring!"; |
| 109 } else { |
| 110 // TODO(carlosk); Must handle errors! |
| 111 CHECK_EQ(result, MOJO_RESULT_OK); |
| 112 } |
| 113 } |
| 114 |
| 115 void MojoStreamWriter::Finalize() { |
| 116 DCHECK(data_producer_handle_.is_valid()); |
| 117 if (buffer_ != nullptr) { |
| 118 CHECK_EQ(mojo::EndWriteDataRaw(data_producer_handle_.get(), 0), |
| 119 MOJO_RESULT_OK); |
| 120 buffer_size_ = -1; |
| 121 } |
| 122 data_producer_handle_.reset(); |
| 123 } |
| 124 |
| 125 void MojoStreamWriter::OnSpaceAvailable(MojoResult result) { |
| 126 LOG(ERROR) << "MojoStreamWriter@" << this << " OnSpaceAvailable - resuming!"; |
| 127 LOG(ERROR) << "MojoStreamWriter@ data_producer_handle_.is_valid(): " |
| 128 << data_producer_handle_.is_valid(); |
| 129 LOG(ERROR) << "MojoStreamWriter@ result: " << result; |
| 130 if (result == MOJO_RESULT_OK) { |
| 131 CHECK(data_producer_handle_.is_valid()); |
| 132 controller_->Resume(); |
| 133 return; |
| 134 } |
| 135 controller_->Cancel(); |
| 136 } |
| 137 |
| 138 } // namespace content |
| OLD | NEW |