OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/plugin_download_helper.h" |
| 6 |
| 7 #if defined(OS_WIN) |
| 8 #include <windows.h> |
| 9 |
| 10 #include "base/file_util.h" |
| 11 #include "chrome/browser/net/url_request_tracking.h" |
| 12 #include "net/base/io_buffer.h" |
| 13 |
| 14 PluginDownloadUrlHelper::PluginDownloadUrlHelper( |
| 15 const std::string& download_url, |
| 16 int source_child_unique_id, |
| 17 gfx::NativeWindow caller_window, |
| 18 PluginDownloadUrlHelper::DownloadDelegate* delegate) |
| 19 : download_file_request_(NULL), |
| 20 download_file_buffer_(new net::IOBuffer(kDownloadFileBufferSize)), |
| 21 download_file_caller_window_(caller_window), |
| 22 download_url_(download_url), |
| 23 download_source_child_unique_id_(source_child_unique_id), |
| 24 delegate_(delegate) { |
| 25 memset(download_file_buffer_->data(), 0, kDownloadFileBufferSize); |
| 26 download_file_.reset(new net::FileStream()); |
| 27 } |
| 28 |
| 29 PluginDownloadUrlHelper::~PluginDownloadUrlHelper() { |
| 30 if (download_file_request_) { |
| 31 delete download_file_request_; |
| 32 download_file_request_ = NULL; |
| 33 } |
| 34 } |
| 35 |
| 36 void PluginDownloadUrlHelper::InitiateDownload( |
| 37 URLRequestContext* request_context) { |
| 38 download_file_request_ = new URLRequest(GURL(download_url_), this); |
| 39 chrome_browser_net::SetOriginProcessUniqueIDForRequest( |
| 40 download_source_child_unique_id_, download_file_request_); |
| 41 download_file_request_->set_context(request_context); |
| 42 download_file_request_->Start(); |
| 43 } |
| 44 |
| 45 void PluginDownloadUrlHelper::OnAuthRequired( |
| 46 URLRequest* request, |
| 47 net::AuthChallengeInfo* auth_info) { |
| 48 URLRequest::Delegate::OnAuthRequired(request, auth_info); |
| 49 DownloadCompletedHelper(false); |
| 50 } |
| 51 |
| 52 void PluginDownloadUrlHelper::OnSSLCertificateError( |
| 53 URLRequest* request, |
| 54 int cert_error, |
| 55 net::X509Certificate* cert) { |
| 56 URLRequest::Delegate::OnSSLCertificateError(request, cert_error, cert); |
| 57 DownloadCompletedHelper(false); |
| 58 } |
| 59 |
| 60 void PluginDownloadUrlHelper::OnResponseStarted(URLRequest* request) { |
| 61 if (!download_file_->IsOpen()) { |
| 62 // This is safe because once the temp file has been safely created, an |
| 63 // attacker can't drop a symlink etc into place. |
| 64 file_util::CreateTemporaryFile(&download_file_path_); |
| 65 download_file_->Open(download_file_path_, |
| 66 base::PLATFORM_FILE_CREATE_ALWAYS | |
| 67 base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE); |
| 68 if (!download_file_->IsOpen()) { |
| 69 NOTREACHED(); |
| 70 OnDownloadCompleted(request); |
| 71 return; |
| 72 } |
| 73 } |
| 74 if (!request->status().is_success()) { |
| 75 OnDownloadCompleted(request); |
| 76 } else { |
| 77 // Initiate a read. |
| 78 int bytes_read = 0; |
| 79 if (!request->Read(download_file_buffer_, kDownloadFileBufferSize, |
| 80 &bytes_read)) { |
| 81 // If the error is not an IO pending, then we're done |
| 82 // reading. |
| 83 if (!request->status().is_io_pending()) { |
| 84 OnDownloadCompleted(request); |
| 85 } |
| 86 } else if (bytes_read == 0) { |
| 87 OnDownloadCompleted(request); |
| 88 } else { |
| 89 OnReadCompleted(request, bytes_read); |
| 90 } |
| 91 } |
| 92 } |
| 93 |
| 94 void PluginDownloadUrlHelper::OnReadCompleted(URLRequest* request, |
| 95 int bytes_read) { |
| 96 DCHECK(download_file_->IsOpen()); |
| 97 |
| 98 if (bytes_read == 0) { |
| 99 OnDownloadCompleted(request); |
| 100 return; |
| 101 } |
| 102 |
| 103 int request_bytes_read = bytes_read; |
| 104 |
| 105 while (request->status().is_success()) { |
| 106 int bytes_written = download_file_->Write(download_file_buffer_->data(), |
| 107 request_bytes_read, NULL); |
| 108 DCHECK((bytes_written < 0) || (bytes_written == request_bytes_read)); |
| 109 |
| 110 if ((bytes_written < 0) || (bytes_written != request_bytes_read)) { |
| 111 DownloadCompletedHelper(false); |
| 112 break; |
| 113 } |
| 114 |
| 115 // Start reading |
| 116 request_bytes_read = 0; |
| 117 if (!request->Read(download_file_buffer_, kDownloadFileBufferSize, |
| 118 &request_bytes_read)) { |
| 119 if (!request->status().is_io_pending()) { |
| 120 // If the error is not an IO pending, then we're done |
| 121 // reading. |
| 122 OnDownloadCompleted(request); |
| 123 } |
| 124 break; |
| 125 } else if (request_bytes_read == 0) { |
| 126 OnDownloadCompleted(request); |
| 127 break; |
| 128 } |
| 129 } |
| 130 } |
| 131 |
| 132 void PluginDownloadUrlHelper::OnDownloadCompleted(URLRequest* request) { |
| 133 bool success = true; |
| 134 if (!request->status().is_success()) { |
| 135 success = false; |
| 136 } else if (!download_file_->IsOpen()) { |
| 137 success = false; |
| 138 } |
| 139 |
| 140 DownloadCompletedHelper(success); |
| 141 } |
| 142 |
| 143 void PluginDownloadUrlHelper::DownloadCompletedHelper(bool success) { |
| 144 if (download_file_->IsOpen()) { |
| 145 download_file_.reset(); |
| 146 } |
| 147 |
| 148 if (success) { |
| 149 FilePath new_download_file_path = |
| 150 download_file_path_.DirName().AppendASCII( |
| 151 download_file_request_->url().ExtractFileName()); |
| 152 |
| 153 file_util::Delete(new_download_file_path, false); |
| 154 |
| 155 if (!file_util::ReplaceFileW(download_file_path_, |
| 156 new_download_file_path)) { |
| 157 DLOG(ERROR) << "Failed to rename file:" |
| 158 << download_file_path_.value() |
| 159 << " to file:" |
| 160 << new_download_file_path.value(); |
| 161 } else { |
| 162 download_file_path_ = new_download_file_path; |
| 163 } |
| 164 } |
| 165 |
| 166 if (delegate_) { |
| 167 delegate_->OnDownloadCompleted(download_file_path_, success); |
| 168 } else { |
| 169 std::wstring path = download_file_path_.value(); |
| 170 COPYDATASTRUCT download_file_data = {0}; |
| 171 download_file_data.cbData = |
| 172 static_cast<unsigned long>((path.length() + 1) * sizeof(wchar_t)); |
| 173 download_file_data.lpData = const_cast<wchar_t *>(path.c_str()); |
| 174 download_file_data.dwData = success; |
| 175 |
| 176 if (::IsWindow(download_file_caller_window_)) { |
| 177 ::SendMessage(download_file_caller_window_, WM_COPYDATA, NULL, |
| 178 reinterpret_cast<LPARAM>(&download_file_data)); |
| 179 } |
| 180 } |
| 181 |
| 182 // Don't access any members after this. |
| 183 delete this; |
| 184 } |
| 185 |
| 186 #endif // OS_WIN |
| 187 |
| 188 |
| 189 |
| 190 |
OLD | NEW |