1 // Copyright (c) 2011 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 net::URLRequestContext* request_context) { 38 download_file_request_ = new net::URLRequest(GURL(download_url_), this); 39 chrome_browser_net::SetOriginPIDForRequest( 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 net::URLRequest* request, 47 net::AuthChallengeInfo* auth_info) { 48 net::URLRequest::Delegate::OnAuthRequired(request, auth_info); 49 DownloadCompletedHelper(false); 50 } 51 52 void PluginDownloadUrlHelper::OnSSLCertificateError( 53 net::URLRequest* request, 54 int cert_error, 55 net::X509Certificate* cert) { 56 net::URLRequest::Delegate::OnSSLCertificateError(request, cert_error, cert); 57 DownloadCompletedHelper(false); 58 } 59 60 void PluginDownloadUrlHelper::OnResponseStarted(net::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(net::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(net::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