OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "net/url_request/url_request_file_dir_job.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/compiler_specific.h" | |
9 #include "base/message_loop/message_loop.h" | |
10 #include "base/profiler/scoped_tracker.h" | |
11 #include "base/strings/sys_string_conversions.h" | |
12 #include "base/strings/utf_string_conversions.h" | |
13 #include "base/time/time.h" | |
14 #include "net/base/io_buffer.h" | |
15 #include "net/base/net_errors.h" | |
16 #include "net/base/net_util.h" | |
17 #include "net/url_request/url_request_status.h" | |
18 #include "url/gurl.h" | |
19 | |
20 #if defined(OS_POSIX) | |
21 #include <sys/stat.h> | |
22 #endif | |
23 | |
24 namespace net { | |
25 | |
26 URLRequestFileDirJob::URLRequestFileDirJob(URLRequest* request, | |
27 NetworkDelegate* network_delegate, | |
28 const base::FilePath& dir_path) | |
29 : URLRequestJob(request, network_delegate), | |
30 lister_(dir_path, this), | |
31 dir_path_(dir_path), | |
32 canceled_(false), | |
33 list_complete_(false), | |
34 wrote_header_(false), | |
35 read_pending_(false), | |
36 read_buffer_length_(0), | |
37 weak_factory_(this) { | |
38 } | |
39 | |
40 void URLRequestFileDirJob::StartAsync() { | |
41 lister_.Start(); | |
42 | |
43 NotifyHeadersComplete(); | |
44 } | |
45 | |
46 void URLRequestFileDirJob::Start() { | |
47 // Start reading asynchronously so that all error reporting and data | |
48 // callbacks happen as they would for network requests. | |
49 base::MessageLoop::current()->PostTask( | |
50 FROM_HERE, | |
51 base::Bind(&URLRequestFileDirJob::StartAsync, | |
52 weak_factory_.GetWeakPtr())); | |
53 } | |
54 | |
55 void URLRequestFileDirJob::Kill() { | |
56 if (canceled_) | |
57 return; | |
58 | |
59 canceled_ = true; | |
60 | |
61 if (!list_complete_) | |
62 lister_.Cancel(); | |
63 | |
64 URLRequestJob::Kill(); | |
65 | |
66 weak_factory_.InvalidateWeakPtrs(); | |
67 } | |
68 | |
69 bool URLRequestFileDirJob::ReadRawData(IOBuffer* buf, int buf_size, | |
70 int* bytes_read) { | |
71 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. | |
72 tracked_objects::ScopedTracker tracking_profile( | |
73 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
74 "423948 URLRequestFileDirJob::ReadRawData")); | |
75 | |
76 DCHECK(bytes_read); | |
77 *bytes_read = 0; | |
78 | |
79 if (is_done()) | |
80 return true; | |
81 | |
82 if (FillReadBuffer(buf->data(), buf_size, bytes_read)) | |
83 return true; | |
84 | |
85 // We are waiting for more data | |
86 read_pending_ = true; | |
87 read_buffer_ = buf; | |
88 read_buffer_length_ = buf_size; | |
89 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); | |
90 return false; | |
91 } | |
92 | |
93 bool URLRequestFileDirJob::GetMimeType(std::string* mime_type) const { | |
94 *mime_type = "text/html"; | |
95 return true; | |
96 } | |
97 | |
98 bool URLRequestFileDirJob::GetCharset(std::string* charset) { | |
99 // All the filenames are converted to UTF-8 before being added. | |
100 *charset = "utf-8"; | |
101 return true; | |
102 } | |
103 | |
104 void URLRequestFileDirJob::OnListFile( | |
105 const DirectoryLister::DirectoryListerData& data) { | |
106 // We wait to write out the header until we get the first file, so that we | |
107 // can catch errors from DirectoryLister and show an error page. | |
108 if (!wrote_header_) { | |
109 #if defined(OS_WIN) | |
110 const base::string16& title = dir_path_.value(); | |
111 #elif defined(OS_POSIX) | |
112 // TODO(jungshik): Add SysNativeMBToUTF16 to sys_string_conversions. | |
113 // On Mac, need to add NFKC->NFC conversion either here or in file_path. | |
114 // On Linux, the file system encoding is not defined, but we assume that | |
115 // SysNativeMBToWide takes care of it at least for now. We can try something | |
116 // more sophisticated if necessary later. | |
117 const base::string16& title = base::WideToUTF16( | |
118 base::SysNativeMBToWide(dir_path_.value())); | |
119 #endif | |
120 data_.append(GetDirectoryListingHeader(title)); | |
121 wrote_header_ = true; | |
122 } | |
123 | |
124 #if defined(OS_WIN) | |
125 std::string raw_bytes; // Empty on Windows means UTF-8 encoded name. | |
126 #elif defined(OS_POSIX) | |
127 // TOOD(jungshik): The same issue as for the directory name. | |
128 base::FilePath filename = data.info.GetName(); | |
129 const std::string& raw_bytes = filename.value(); | |
130 #endif | |
131 data_.append(GetDirectoryListingEntry( | |
132 data.info.GetName().LossyDisplayName(), | |
133 raw_bytes, | |
134 data.info.IsDirectory(), | |
135 data.info.GetSize(), | |
136 data.info.GetLastModifiedTime())); | |
137 | |
138 // TODO(darin): coalesce more? | |
139 CompleteRead(); | |
140 } | |
141 | |
142 void URLRequestFileDirJob::OnListDone(int error) { | |
143 DCHECK(!canceled_); | |
144 if (error != OK) { | |
145 read_pending_ = false; | |
146 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, error)); | |
147 } else { | |
148 list_complete_ = true; | |
149 CompleteRead(); | |
150 } | |
151 } | |
152 | |
153 URLRequestFileDirJob::~URLRequestFileDirJob() {} | |
154 | |
155 void URLRequestFileDirJob::CompleteRead() { | |
156 if (read_pending_) { | |
157 int bytes_read; | |
158 if (FillReadBuffer(read_buffer_->data(), read_buffer_length_, | |
159 &bytes_read)) { | |
160 // We completed the read, so reset the read buffer. | |
161 read_pending_ = false; | |
162 read_buffer_ = NULL; | |
163 read_buffer_length_ = 0; | |
164 | |
165 SetStatus(URLRequestStatus()); | |
166 NotifyReadComplete(bytes_read); | |
167 } else { | |
168 NOTREACHED(); | |
169 // TODO: Better error code. | |
170 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, 0)); | |
171 } | |
172 } | |
173 } | |
174 | |
175 bool URLRequestFileDirJob::FillReadBuffer(char* buf, int buf_size, | |
176 int* bytes_read) { | |
177 DCHECK(bytes_read); | |
178 | |
179 *bytes_read = 0; | |
180 | |
181 int count = std::min(buf_size, static_cast<int>(data_.size())); | |
182 if (count) { | |
183 memcpy(buf, &data_[0], count); | |
184 data_.erase(0, count); | |
185 *bytes_read = count; | |
186 return true; | |
187 } else if (list_complete_) { | |
188 // EOF | |
189 return true; | |
190 } | |
191 return false; | |
192 } | |
193 | |
194 } // namespace net | |
OLD | NEW |