1 // Copyright 2014 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 "mojo/edk/js/drain_data.h" 6 7 #include <stddef.h> 8 #include <stdint.h> 9 10 #include "base/bind.h" 11 #include "gin/array_buffer.h" 12 #include "gin/converter.h" 13 #include "gin/dictionary.h" 14 #include "gin/per_context_data.h" 15 #include "gin/per_isolate_data.h" 16 #include "mojo/public/cpp/system/core.h" 17 18 namespace mojo { 19 namespace edk { 20 namespace js { 21 22 DrainData::DrainData(v8::Isolate* isolate, mojo::Handle handle) 23 : isolate_(isolate), handle_(DataPipeConsumerHandle(handle.value())) { 24 v8::Handle<v8::Context> context(isolate_->GetCurrentContext()); 25 runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr(); 26 27 WaitForData(); 28 } 29 30 v8::Handle<v8::Value> DrainData::GetPromise() { 31 CHECK(resolver_.IsEmpty()); 32 v8::Handle<v8::Promise::Resolver> resolver( 33 v8::Promise::Resolver::New(isolate_)); 34 resolver_.Reset(isolate_, resolver); 35 return resolver->GetPromise(); 36 } 37 38 DrainData::~DrainData() { 39 resolver_.Reset(); 40 } 41 42 void DrainData::WaitForData() { 43 handle_watcher_.Start( 44 handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, 45 base::Bind(&DrainData::DataReady, base::Unretained(this))); 46 } 47 48 void DrainData::DataReady(MojoResult result) { 49 if (result != MOJO_RESULT_OK) { 50 DeliverData(result); 51 return; 52 } 53 while (result == MOJO_RESULT_OK) { 54 result = ReadData(); 55 if (result == MOJO_RESULT_SHOULD_WAIT) 56 WaitForData(); 57 else if (result != MOJO_RESULT_OK) 58 DeliverData(result); 59 } 60 } 61 62 MojoResult DrainData::ReadData() { 63 const void* buffer; 64 uint32_t num_bytes = 0; 65 MojoResult result = BeginReadDataRaw( 66 handle_.get(), &buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE); 67 if (result != MOJO_RESULT_OK) 68 return result; 69 const char* p = static_cast<const char*>(buffer); 70 DataBuffer* data_buffer = new DataBuffer(p, p + num_bytes); 71 data_buffers_.push_back(data_buffer); 72 return EndReadDataRaw(handle_.get(), num_bytes); 73 } 74 75 void DrainData::DeliverData(MojoResult result) { 76 if (!runner_) { 77 delete this; 78 return; 79 } 80 81 size_t total_bytes = 0; 82 for (unsigned i = 0; i < data_buffers_.size(); i++) 83 total_bytes += data_buffers_[i]->size(); 84 85 // Create a total_bytes length ArrayBuffer return value. 86 gin::Runner::Scope scope(runner_.get()); 87 v8::Handle<v8::ArrayBuffer> array_buffer = 88 v8::ArrayBuffer::New(isolate_, total_bytes); 89 gin::ArrayBuffer buffer; 90 ConvertFromV8(isolate_, array_buffer, &buffer); 91 CHECK_EQ(total_bytes, buffer.num_bytes()); 92 93 // Copy the data_buffers into the ArrayBuffer. 94 char* array_buffer_ptr = static_cast<char*>(buffer.bytes()); 95 size_t offset = 0; 96 for (size_t i = 0; i < data_buffers_.size(); i++) { 97 size_t num_bytes = data_buffers_[i]->size(); 98 if (num_bytes == 0) 99 continue; 100 const char* data_buffer_ptr = &((*data_buffers_[i])[0]); 101 memcpy(array_buffer_ptr + offset, data_buffer_ptr, num_bytes); 102 offset += num_bytes; 103 } 104 105 // The "settled" value of the promise always includes all of the data 106 // that was read before either an error occurred or the remote pipe handle 107 // was closed. The latter is indicated by MOJO_RESULT_FAILED_PRECONDITION. 108 109 v8::Handle<v8::Promise::Resolver> resolver( 110 v8::Local<v8::Promise::Resolver>::New(isolate_, resolver_)); 111 112 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(isolate_); 113 dictionary.Set("result", result); 114 dictionary.Set("buffer", array_buffer); 115 v8::Handle<v8::Value> settled_value(ConvertToV8(isolate_, dictionary)); 116 117 if (result == MOJO_RESULT_FAILED_PRECONDITION) 118 resolver->Resolve(settled_value); 119 else 120 resolver->Reject(settled_value); 121 122 delete this; 123 } 124 125 } // namespace js 126 } // namespace edk 127 } // namespace mojo 128