Chromium Code Reviews| Index: content/browser/devtools/devtools_io_context.cc |
| diff --git a/content/browser/devtools/devtools_io_context.cc b/content/browser/devtools/devtools_io_context.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..70cc7706407ccec09d7619ba25d41b711858b5fe |
| --- /dev/null |
| +++ b/content/browser/devtools/devtools_io_context.cc |
| @@ -0,0 +1,129 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/devtools/devtools_io_context.h" |
| + |
| +#include "base/files/file.h" |
| +#include "base/files/file_util.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/strings/string_util.h" |
| +#include "base/third_party/icu/icu_utf.h" |
| +#include "content/public/browser/browser_thread.h" |
| + |
| +namespace content { |
| +namespace devtools { |
| + |
| +namespace { |
| +unsigned s_last_stream_id = 0; |
| +} |
| + |
| +using Stream = DevToolsIOContext::Stream; |
| + |
| +Stream::Stream() |
| + : base::RefCountedDeleteOnMessageLoop<Stream>( |
| + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)), |
| + id_(base::IntToString(++s_last_stream_id)), |
| + had_errors_(false), |
| + last_read_pos_(0) {} |
| + |
| +Stream::~Stream() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| +} |
| + |
| +bool Stream::InitOnFileThreadIdNeeded() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| + if (had_errors_) |
| + return false; |
| + if (file_.IsValid()) |
| + return true; |
| + base::FilePath temp_path; |
| + if (!base::CreateTemporaryFile(&temp_path)) { |
| + LOG(ERROR) << "Failed to create temporary file"; |
| + had_errors_ = true; |
| + return false; |
| + } |
| + const unsigned flags = base::File::FLAG_OPEN_TRUNCATED | |
| + base::File::FLAG_APPEND | base::File::FLAG_READ | |
| + base::File::FLAG_DELETE_ON_CLOSE; |
| + file_.Initialize(temp_path, flags); |
| + if (!file_.IsValid()) { |
| + LOG(ERROR) << "Failed to open temporary file: " << temp_path.value() |
| + << ", " << base::File::ErrorToString(file_.error_details()); |
| + had_errors_ = true; |
| + DeleteFile(temp_path, false); |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +void Stream::Read(off_t position, size_t max_size, ReadCallback callback) { |
|
pfeldman
2015/08/24 18:17:55
DCHECK file thread, also don't call on main thread
|
| + Status status = StatusFailure; |
| + scoped_refptr<base::RefCountedString> data; |
| + |
| + if (file_.IsValid()) { |
| + std::string buffer; |
| + buffer.resize(max_size); |
| + if (position < 0) |
| + position = last_read_pos_; |
| + int size_got = file_.ReadNoBestEffort(position, &*buffer.begin(), max_size); |
| + if (size_got < 0) { |
| + LOG(ERROR) << "Failed to read temporary file"; |
| + had_errors_ = true; |
| + file_.Close(); |
| + } else { |
| + // Provided client has requested sufficient large block, make their |
| + // life easier by not truncating in the middle of a UTF-8 character. |
| + if (size_got > 6 && !CBU8_IS_SINGLE(buffer[size_got - 1])) { |
| + base::TruncateUTF8ToByteSize(buffer, size_got, &buffer); |
| + size_got = buffer.size(); |
| + } else { |
| + buffer.resize(size_got); |
| + } |
| + data = base::RefCountedString::TakeString(&buffer); |
| + status = size_got ? StatusSuccess : StatusEOF; |
| + last_read_pos_ = position + size_got; |
| + } |
| + } |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(callback, data, status)); |
| +} |
| + |
| +void Stream::Append(const scoped_refptr<base::RefCountedString>& data) { |
| + if (!InitOnFileThreadIdNeeded()) |
| + return; |
| + const std::string& buffer = data->data(); |
| + int size_written = file_.WriteAtCurrentPos(&*buffer.begin(), buffer.size()); |
| + if (size_written != static_cast<int>(buffer.size())) { |
| + LOG(ERROR) << "Failed to write temporary file"; |
| + had_errors_ = true; |
| + file_.Close(); |
| + } |
| +} |
| + |
| +DevToolsIOContext::DevToolsIOContext() {} |
| + |
| +DevToolsIOContext::~DevToolsIOContext() {} |
| + |
| +scoped_refptr<Stream> DevToolsIOContext::CreateTempFileBackedStream() { |
| + scoped_refptr<Stream> result = new Stream(); |
| + bool inserted = streams_.insert(std::make_pair(result->id(), result)).second; |
| + DCHECK(inserted); |
| + return result; |
| +} |
| + |
| +scoped_refptr<Stream> DevToolsIOContext::GetById(const std::string& id) { |
| + StreamsMap::const_iterator it = streams_.find(id); |
| + return it == streams_.end() ? scoped_refptr<Stream>() : it->second; |
| +} |
| + |
| +bool DevToolsIOContext::Close(const std::string& id) { |
| + return streams_.erase(id) == 1; |
| +} |
| + |
| +void DevToolsIOContext::DiscardAllStreams() { |
| + return streams_.clear(); |
| +} |
| + |
| +} // namespace devtools |
| +} // namespace content |