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; | |
22 | 19 |
23 // TODO(darin): Use the buffer sizing algorithm from AsyncResourceHandler. | 20 // TODO(darin): Use the buffer sizing algorithm from AsyncResourceHandler. |
24 static const int kReadBufSize = 32768; | 21 static const int kReadBufSize = 32768; |
25 | 22 |
26 RedirectToFileResourceHandler::RedirectToFileResourceHandler( | 23 RedirectToFileResourceHandler::RedirectToFileResourceHandler( |
27 ResourceHandler* next_handler, | 24 ResourceHandler* next_handler, |
28 int process_id, | 25 int process_id, |
29 ResourceDispatcherHost* host) | 26 ResourceDispatcherHost* host) |
30 : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 27 : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
31 host_(host), | 28 host_(host), |
(...skipping 20 matching lines...) Expand all Loading... |
52 ResourceResponse* response, | 49 ResourceResponse* response, |
53 bool* defer) { | 50 bool* defer) { |
54 return next_handler_->OnRequestRedirected(request_id, new_url, response, | 51 return next_handler_->OnRequestRedirected(request_id, new_url, response, |
55 defer); | 52 defer); |
56 } | 53 } |
57 | 54 |
58 bool RedirectToFileResourceHandler::OnResponseStarted( | 55 bool RedirectToFileResourceHandler::OnResponseStarted( |
59 int request_id, | 56 int request_id, |
60 ResourceResponse* response) { | 57 ResourceResponse* response) { |
61 if (response->response_head.status.is_success()) { | 58 if (response->response_head.status.is_success()) { |
62 DCHECK(deletable_file_ && !deletable_file_->path().empty()); | 59 DCHECK(!file_path_.empty()); |
63 response->response_head.download_file_path = deletable_file_->path(); | 60 response->response_head.download_file_path = file_path_; |
64 } | 61 } |
65 return next_handler_->OnResponseStarted(request_id, response); | 62 return next_handler_->OnResponseStarted(request_id, response); |
66 } | 63 } |
67 | 64 |
68 bool RedirectToFileResourceHandler::OnWillStart(int request_id, | 65 bool RedirectToFileResourceHandler::OnWillStart(int request_id, |
69 const GURL& url, | 66 const GURL& url, |
70 bool* defer) { | 67 bool* defer) { |
71 request_id_ = request_id; | 68 request_id_ = request_id; |
72 if (!deletable_file_) { | 69 if (file_path_.empty()) { |
73 // Defer starting the request until we have created the temporary file. | 70 // Defer starting the request until we have created the temporary file. |
74 // TODO(darin): This is sub-optimal. We should not delay starting the | 71 // TODO(darin): This is sub-optimal. We should not delay starting the |
75 // network request like this. | 72 // network request like this. |
76 *defer = true; | 73 *defer = true; |
77 base::FileUtilProxy::CreateTemporary( | 74 base::FileUtilProxy::CreateTemporary( |
78 ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE), | 75 ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE), |
79 callback_factory_.NewCallback( | 76 callback_factory_.NewCallback( |
80 &RedirectToFileResourceHandler::DidCreateTemporaryFile)); | 77 &RedirectToFileResourceHandler::DidCreateTemporaryFile)); |
81 return true; | 78 return true; |
82 } | 79 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 | 116 |
120 // We use the buffer's offset field to record the end of the buffer. | 117 // We use the buffer's offset field to record the end of the buffer. |
121 | 118 |
122 int new_offset = buf_->offset() + *bytes_read; | 119 int new_offset = buf_->offset() + *bytes_read; |
123 DCHECK(new_offset <= buf_->capacity()); | 120 DCHECK(new_offset <= buf_->capacity()); |
124 buf_->set_offset(new_offset); | 121 buf_->set_offset(new_offset); |
125 | 122 |
126 if (BufIsFull()) | 123 if (BufIsFull()) |
127 host_->PauseRequest(process_id_, request_id, true); | 124 host_->PauseRequest(process_id_, request_id, true); |
128 | 125 |
129 if (*bytes_read > 0) | |
130 next_handler_->OnDataDownloaded(request_id, *bytes_read); | |
131 | |
132 return WriteMore(); | 126 return WriteMore(); |
133 } | 127 } |
134 | 128 |
135 bool RedirectToFileResourceHandler::OnResponseCompleted( | 129 bool RedirectToFileResourceHandler::OnResponseCompleted( |
136 int request_id, | 130 int request_id, |
137 const URLRequestStatus& status, | 131 const URLRequestStatus& status, |
138 const std::string& security_info) { | 132 const std::string& security_info) { |
139 return next_handler_->OnResponseCompleted(request_id, status, security_info); | 133 return next_handler_->OnResponseCompleted(request_id, status, security_info); |
140 } | 134 } |
141 | 135 |
142 void RedirectToFileResourceHandler::OnRequestClosed() { | 136 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 |
143 // We require this explicit call to Close since file_stream_ was constructed | 142 // We require this explicit call to Close since file_stream_ was constructed |
144 // directly from a PlatformFile. | 143 // directly from a PlatformFile. |
145 file_stream_->Close(); | 144 file_stream_->Close(); |
146 file_stream_.reset(); | 145 file_stream_.reset(); |
147 deletable_file_ = NULL; | |
148 | 146 |
149 next_handler_->OnRequestClosed(); | 147 // TODO(dumi): delete the temp file when it's no longer needed. |
| 148 // TODO(dumi): revoke the privilege to upload this file. |
| 149 // base::FileUtilProxy::Delete( |
| 150 // ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE), |
| 151 // file_path_, NULL); |
150 } | 152 } |
151 | 153 |
152 RedirectToFileResourceHandler::~RedirectToFileResourceHandler() { | 154 RedirectToFileResourceHandler::~RedirectToFileResourceHandler() { |
153 DCHECK(!file_stream_.get()); | 155 DCHECK(!file_stream_.get()); |
154 } | 156 } |
155 | 157 |
156 void RedirectToFileResourceHandler::DidCreateTemporaryFile( | 158 void RedirectToFileResourceHandler::DidCreateTemporaryFile( |
157 base::PlatformFileError /*error_code*/, | 159 base::PlatformFileError /*error_code*/, |
158 base::PassPlatformFile file_handle, | 160 base::PassPlatformFile file_handle, |
159 FilePath file_path) { | 161 FilePath file_path) { |
160 deletable_file_ = DeletableFileReference::GetOrCreate( | 162 file_path_ = file_path; |
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 host_->RegisterDownloadedTempFile( | 166 ChildProcessSecurityPolicy::GetInstance()->GrantUploadFile( |
167 process_id_, request_id_, deletable_file_.get()); | 167 process_id_, file_path); |
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 |