OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/renderer_host/redirect_to_file_resource_handler.h" | 5 #include "chrome/browser/renderer_host/redirect_to_file_resource_handler.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/file_util_proxy.h" | 8 #include "base/file_util_proxy.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/platform_file.h" | 10 #include "base/platform_file.h" |
11 #include "base/task.h" | 11 #include "base/task.h" |
12 #include "chrome/browser/child_process_security_policy.h" | 12 #include "chrome/browser/child_process_security_policy.h" |
13 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" | 13 #include "chrome/browser/renderer_host/resource_dispatcher_host.h" |
14 #include "chrome/common/resource_response.h" | 14 #include "chrome/common/resource_response.h" |
15 #include "net/base/file_stream.h" | 15 #include "net/base/file_stream.h" |
16 #include "net/base/io_buffer.h" | 16 #include "net/base/io_buffer.h" |
17 #include "net/base/mime_sniffer.h" | 17 #include "net/base/mime_sniffer.h" |
18 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
| 19 #include "webkit/blob/deletable_file_reference.h" |
| 20 |
| 21 using webkit_blob::DeletableFileReference; |
19 | 22 |
20 // TODO(darin): Use the buffer sizing algorithm from AsyncResourceHandler. | 23 // TODO(darin): Use the buffer sizing algorithm from AsyncResourceHandler. |
21 static const int kReadBufSize = 32768; | 24 static const int kReadBufSize = 32768; |
22 | 25 |
23 RedirectToFileResourceHandler::RedirectToFileResourceHandler( | 26 RedirectToFileResourceHandler::RedirectToFileResourceHandler( |
24 ResourceHandler* next_handler, | 27 ResourceHandler* next_handler, |
25 int process_id, | 28 int process_id, |
26 ResourceDispatcherHost* host) | 29 ResourceDispatcherHost* host) |
27 : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 30 : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
28 host_(host), | 31 host_(host), |
(...skipping 20 matching lines...) Expand all Loading... |
49 ResourceResponse* response, | 52 ResourceResponse* response, |
50 bool* defer) { | 53 bool* defer) { |
51 return next_handler_->OnRequestRedirected(request_id, new_url, response, | 54 return next_handler_->OnRequestRedirected(request_id, new_url, response, |
52 defer); | 55 defer); |
53 } | 56 } |
54 | 57 |
55 bool RedirectToFileResourceHandler::OnResponseStarted( | 58 bool RedirectToFileResourceHandler::OnResponseStarted( |
56 int request_id, | 59 int request_id, |
57 ResourceResponse* response) { | 60 ResourceResponse* response) { |
58 if (response->response_head.status.is_success()) { | 61 if (response->response_head.status.is_success()) { |
59 DCHECK(!file_path_.empty()); | 62 DCHECK(deletable_file_ && !deletable_file_->path().empty()); |
60 response->response_head.download_file_path = file_path_; | 63 response->response_head.download_file_path = deletable_file_->path(); |
61 } | 64 } |
62 return next_handler_->OnResponseStarted(request_id, response); | 65 return next_handler_->OnResponseStarted(request_id, response); |
63 } | 66 } |
64 | 67 |
65 bool RedirectToFileResourceHandler::OnWillStart(int request_id, | 68 bool RedirectToFileResourceHandler::OnWillStart(int request_id, |
66 const GURL& url, | 69 const GURL& url, |
67 bool* defer) { | 70 bool* defer) { |
68 request_id_ = request_id; | 71 request_id_ = request_id; |
69 if (file_path_.empty()) { | 72 if (!deletable_file_) { |
70 // Defer starting the request until we have created the temporary file. | 73 // Defer starting the request until we have created the temporary file. |
71 // TODO(darin): This is sub-optimal. We should not delay starting the | 74 // TODO(darin): This is sub-optimal. We should not delay starting the |
72 // network request like this. | 75 // network request like this. |
73 *defer = true; | 76 *defer = true; |
74 base::FileUtilProxy::CreateTemporary( | 77 base::FileUtilProxy::CreateTemporary( |
75 ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE), | 78 ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE), |
76 callback_factory_.NewCallback( | 79 callback_factory_.NewCallback( |
77 &RedirectToFileResourceHandler::DidCreateTemporaryFile)); | 80 &RedirectToFileResourceHandler::DidCreateTemporaryFile)); |
78 return true; | 81 return true; |
79 } | 82 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 | 119 |
117 // We use the buffer's offset field to record the end of the buffer. | 120 // We use the buffer's offset field to record the end of the buffer. |
118 | 121 |
119 int new_offset = buf_->offset() + *bytes_read; | 122 int new_offset = buf_->offset() + *bytes_read; |
120 DCHECK(new_offset <= buf_->capacity()); | 123 DCHECK(new_offset <= buf_->capacity()); |
121 buf_->set_offset(new_offset); | 124 buf_->set_offset(new_offset); |
122 | 125 |
123 if (BufIsFull()) | 126 if (BufIsFull()) |
124 host_->PauseRequest(process_id_, request_id, true); | 127 host_->PauseRequest(process_id_, request_id, true); |
125 | 128 |
| 129 if (*bytes_read > 0) |
| 130 next_handler_->OnDataDownloaded(request_id, *bytes_read); |
| 131 |
126 return WriteMore(); | 132 return WriteMore(); |
127 } | 133 } |
128 | 134 |
129 bool RedirectToFileResourceHandler::OnResponseCompleted( | 135 bool RedirectToFileResourceHandler::OnResponseCompleted( |
130 int request_id, | 136 int request_id, |
131 const URLRequestStatus& status, | 137 const URLRequestStatus& status, |
132 const std::string& security_info) { | 138 const std::string& security_info) { |
133 return next_handler_->OnResponseCompleted(request_id, status, security_info); | 139 return next_handler_->OnResponseCompleted(request_id, status, security_info); |
134 } | 140 } |
135 | 141 |
136 void RedirectToFileResourceHandler::OnRequestClosed() { | 142 void RedirectToFileResourceHandler::OnRequestClosed() { |
137 next_handler_->OnRequestClosed(); | |
138 | |
139 // The renderer no longer has a WebURLLoader open to this request, so we can | |
140 // close and unlink the file. | |
141 | |
142 // We require this explicit call to Close since file_stream_ was constructed | 143 // We require this explicit call to Close since file_stream_ was constructed |
143 // directly from a PlatformFile. | 144 // directly from a PlatformFile. |
144 file_stream_->Close(); | 145 file_stream_->Close(); |
145 file_stream_.reset(); | 146 file_stream_.reset(); |
| 147 deletable_file_ = NULL; |
146 | 148 |
147 // TODO(dumi): delete the temp file when it's no longer needed. | 149 next_handler_->OnRequestClosed(); |
148 // TODO(dumi): revoke the privilege to upload this file. | |
149 // base::FileUtilProxy::Delete( | |
150 // ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE), | |
151 // file_path_, NULL); | |
152 } | 150 } |
153 | 151 |
154 RedirectToFileResourceHandler::~RedirectToFileResourceHandler() { | 152 RedirectToFileResourceHandler::~RedirectToFileResourceHandler() { |
155 DCHECK(!file_stream_.get()); | 153 DCHECK(!file_stream_.get()); |
156 } | 154 } |
157 | 155 |
158 void RedirectToFileResourceHandler::DidCreateTemporaryFile( | 156 void RedirectToFileResourceHandler::DidCreateTemporaryFile( |
159 base::PlatformFileError /*error_code*/, | 157 base::PlatformFileError /*error_code*/, |
160 base::PassPlatformFile file_handle, | 158 base::PassPlatformFile file_handle, |
161 FilePath file_path) { | 159 FilePath file_path) { |
162 file_path_ = file_path; | 160 deletable_file_ = DeletableFileReference::GetOrCreate( |
| 161 file_path, |
| 162 ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE)); |
163 file_stream_.reset(new net::FileStream(file_handle.ReleaseValue(), | 163 file_stream_.reset(new net::FileStream(file_handle.ReleaseValue(), |
164 base::PLATFORM_FILE_WRITE | | 164 base::PLATFORM_FILE_WRITE | |
165 base::PLATFORM_FILE_ASYNC)); | 165 base::PLATFORM_FILE_ASYNC)); |
166 ChildProcessSecurityPolicy::GetInstance()->GrantReadFile( | 166 host_->RegisterDownloadedTempFile( |
167 process_id_, file_path); | 167 process_id_, request_id_, deletable_file_.get()); |
168 host_->StartDeferredRequest(process_id_, request_id_); | 168 host_->StartDeferredRequest(process_id_, request_id_); |
169 } | 169 } |
170 | 170 |
171 void RedirectToFileResourceHandler::DidWriteToFile(int result) { | 171 void RedirectToFileResourceHandler::DidWriteToFile(int result) { |
172 write_callback_pending_ = false; | 172 write_callback_pending_ = false; |
173 | 173 |
174 bool failed = false; | 174 bool failed = false; |
175 if (result > 0) { | 175 if (result > 0) { |
176 write_cursor_ += result; | 176 write_cursor_ += result; |
177 failed = !WriteMore(); | 177 failed = !WriteMore(); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 } | 213 } |
214 } | 214 } |
215 | 215 |
216 bool RedirectToFileResourceHandler::BufIsFull() const { | 216 bool RedirectToFileResourceHandler::BufIsFull() const { |
217 // This is a hack to workaround BufferedResourceHandler's inability to | 217 // This is a hack to workaround BufferedResourceHandler's inability to |
218 // deal with a ResourceHandler that returns a buffer size of less than | 218 // deal with a ResourceHandler that returns a buffer size of less than |
219 // 2 * net::kMaxBytesToSniff from its OnWillRead method. | 219 // 2 * net::kMaxBytesToSniff from its OnWillRead method. |
220 // TODO(darin): Fix this retardation! | 220 // TODO(darin): Fix this retardation! |
221 return buf_->RemainingCapacity() <= (2 * net::kMaxBytesToSniff); | 221 return buf_->RemainingCapacity() <= (2 * net::kMaxBytesToSniff); |
222 } | 222 } |
OLD | NEW |