1 // Copyright 2015 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.
5 #include "content/browser/devtools/devtools_io_context.h"
7 #include "base/files/file.h"
8 #include "base/files/file_util.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/third_party/icu/icu_utf.h"
12 #include "content/public/browser/browser_thread.h"
18 unsigned s_last_stream_handle
= 0;
21 using Stream
= DevToolsIOContext::Stream
;
24 : base::RefCountedDeleteOnMessageLoop
<Stream
>(
25 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)),
26 handle_(base::IntToString(++s_last_stream_handle
)),
31 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
34 bool Stream::InitOnFileThreadIfNeeded() {
39 base::FilePath temp_path
;
40 if (!base::CreateTemporaryFile(&temp_path
)) {
41 LOG(ERROR
) << "Failed to create temporary file";
45 const unsigned flags
= base::File::FLAG_OPEN_TRUNCATED
|
46 base::File::FLAG_WRITE
| base::File::FLAG_READ
|
47 base::File::FLAG_DELETE_ON_CLOSE
;
48 file_
.Initialize(temp_path
, flags
);
49 if (!file_
.IsValid()) {
50 LOG(ERROR
) << "Failed to open temporary file: " << temp_path
.value()
51 << ", " << base::File::ErrorToString(file_
.error_details());
53 DeleteFile(temp_path
, false);
59 void Stream::Read(off_t position
, size_t max_size
, ReadCallback callback
) {
60 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
61 base::Bind(&Stream::ReadOnFileThread
, this, position
, max_size
,
65 void Stream::Append(const scoped_refptr
<base::RefCountedString
>& data
) {
66 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
67 base::Bind(&Stream::AppendOnFileThread
, this, data
));
70 void Stream::ReadOnFileThread(off_t position
, size_t max_size
,
71 ReadCallback callback
) {
72 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
73 Status status
= StatusFailure
;
74 scoped_refptr
<base::RefCountedString
> data
;
76 if (file_
.IsValid()) {
78 buffer
.resize(max_size
);
80 position
= last_read_pos_
;
81 int size_got
= file_
.ReadNoBestEffort(position
, &*buffer
.begin(), max_size
);
83 LOG(ERROR
) << "Failed to read temporary file";
87 // Provided client has requested sufficient large block, make their
88 // life easier by not truncating in the middle of a UTF-8 character.
89 if (size_got
> 6 && !CBU8_IS_SINGLE(buffer
[size_got
- 1])) {
90 base::TruncateUTF8ToByteSize(buffer
, size_got
, &buffer
);
91 size_got
= buffer
.size();
93 buffer
.resize(size_got
);
95 data
= base::RefCountedString::TakeString(&buffer
);
96 status
= size_got
? StatusSuccess
: StatusEOF
;
97 last_read_pos_
= position
+ size_got
;
100 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
101 base::Bind(callback
, data
, status
));
104 void Stream::AppendOnFileThread(
105 const scoped_refptr
<base::RefCountedString
>& data
) {
106 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
107 if (!InitOnFileThreadIfNeeded())
109 const std::string
& buffer
= data
->data();
110 int size_written
= file_
.WriteAtCurrentPos(&*buffer
.begin(), buffer
.size());
111 if (size_written
!= static_cast<int>(buffer
.size())) {
112 LOG(ERROR
) << "Failed to write temporary file";
118 DevToolsIOContext::DevToolsIOContext() {}
120 DevToolsIOContext::~DevToolsIOContext() {}
122 scoped_refptr
<Stream
> DevToolsIOContext::CreateTempFileBackedStream() {
123 scoped_refptr
<Stream
> result
= new Stream();
125 streams_
.insert(std::make_pair(result
->handle(), result
)).second
;
130 scoped_refptr
<Stream
>
131 DevToolsIOContext::GetByHandle(const std::string
& handle
) {
132 StreamsMap::const_iterator it
= streams_
.find(handle
);
133 return it
== streams_
.end() ? scoped_refptr
<Stream
>() : it
->second
;
136 bool DevToolsIOContext::Close(const std::string
& handle
) {
137 return streams_
.erase(handle
) == 1;
140 void DevToolsIOContext::DiscardAllStreams() {
141 return streams_
.clear();
144 } // namespace devtools
145 } // namespace content