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.
5 #include "chrome/browser/plugin_download_helper.h"
10 #include "base/file_util.h"
11 #include "net/base/io_buffer.h"
13 PluginDownloadUrlHelper::PluginDownloadUrlHelper(
14 const std::string
& download_url
,
15 gfx::NativeWindow caller_window
,
16 PluginDownloadUrlHelper::DownloadDelegate
* delegate
)
17 : download_file_request_(NULL
),
18 download_file_buffer_(new net::IOBuffer(kDownloadFileBufferSize
)),
19 download_file_caller_window_(caller_window
),
20 download_url_(download_url
),
22 memset(download_file_buffer_
->data(), 0, kDownloadFileBufferSize
);
23 download_file_
.reset(new net::FileStream());
26 PluginDownloadUrlHelper::~PluginDownloadUrlHelper() {
27 if (download_file_request_
) {
28 delete download_file_request_
;
29 download_file_request_
= NULL
;
33 void PluginDownloadUrlHelper::InitiateDownload(
34 net::URLRequestContext
* request_context
) {
35 download_file_request_
= new net::URLRequest(GURL(download_url_
), this);
36 download_file_request_
->set_context(request_context
);
37 download_file_request_
->Start();
40 void PluginDownloadUrlHelper::OnAuthRequired(
41 net::URLRequest
* request
,
42 net::AuthChallengeInfo
* auth_info
) {
43 net::URLRequest::Delegate::OnAuthRequired(request
, auth_info
);
44 DownloadCompletedHelper(false);
47 void PluginDownloadUrlHelper::OnSSLCertificateError(
48 net::URLRequest
* request
,
50 net::X509Certificate
* cert
) {
51 net::URLRequest::Delegate::OnSSLCertificateError(request
, cert_error
, cert
);
52 DownloadCompletedHelper(false);
55 void PluginDownloadUrlHelper::OnResponseStarted(net::URLRequest
* request
) {
56 if (!download_file_
->IsOpen()) {
57 // This is safe because once the temp file has been safely created, an
58 // attacker can't drop a symlink etc into place.
59 file_util::CreateTemporaryFile(&download_file_path_
);
60 download_file_
->Open(download_file_path_
,
61 base::PLATFORM_FILE_CREATE_ALWAYS
|
62 base::PLATFORM_FILE_READ
| base::PLATFORM_FILE_WRITE
);
63 if (!download_file_
->IsOpen()) {
65 OnDownloadCompleted(request
);
69 if (!request
->status().is_success()) {
70 OnDownloadCompleted(request
);
74 if (!request
->Read(download_file_buffer_
, kDownloadFileBufferSize
,
76 // If the error is not an IO pending, then we're done
78 if (!request
->status().is_io_pending()) {
79 OnDownloadCompleted(request
);
81 } else if (bytes_read
== 0) {
82 OnDownloadCompleted(request
);
84 OnReadCompleted(request
, bytes_read
);
89 void PluginDownloadUrlHelper::OnReadCompleted(net::URLRequest
* request
,
91 DCHECK(download_file_
->IsOpen());
93 if (bytes_read
== 0) {
94 OnDownloadCompleted(request
);
98 int request_bytes_read
= bytes_read
;
100 while (request
->status().is_success()) {
101 int bytes_written
= download_file_
->Write(download_file_buffer_
->data(),
102 request_bytes_read
, NULL
);
103 DCHECK((bytes_written
< 0) || (bytes_written
== request_bytes_read
));
105 if ((bytes_written
< 0) || (bytes_written
!= request_bytes_read
)) {
106 DownloadCompletedHelper(false);
111 request_bytes_read
= 0;
112 if (!request
->Read(download_file_buffer_
, kDownloadFileBufferSize
,
113 &request_bytes_read
)) {
114 if (!request
->status().is_io_pending()) {
115 // If the error is not an IO pending, then we're done
117 OnDownloadCompleted(request
);
120 } else if (request_bytes_read
== 0) {
121 OnDownloadCompleted(request
);
127 void PluginDownloadUrlHelper::OnDownloadCompleted(net::URLRequest
* request
) {
129 if (!request
->status().is_success()) {
131 } else if (!download_file_
->IsOpen()) {
135 DownloadCompletedHelper(success
);
138 void PluginDownloadUrlHelper::DownloadCompletedHelper(bool success
) {
139 if (download_file_
->IsOpen()) {
140 download_file_
.reset();
144 FilePath new_download_file_path
=
145 download_file_path_
.DirName().AppendASCII(
146 download_file_request_
->url().ExtractFileName());
148 file_util::Delete(new_download_file_path
, false);
150 if (!file_util::ReplaceFileW(download_file_path_
,
151 new_download_file_path
)) {
152 DLOG(ERROR
) << "Failed to rename file:"
153 << download_file_path_
.value()
155 << new_download_file_path
.value();
157 download_file_path_
= new_download_file_path
;
162 delegate_
->OnDownloadCompleted(download_file_path_
, success
);
164 std::wstring path
= download_file_path_
.value();
165 COPYDATASTRUCT download_file_data
= {0};
166 download_file_data
.cbData
=
167 static_cast<unsigned long>((path
.length() + 1) * sizeof(wchar_t));
168 download_file_data
.lpData
= const_cast<wchar_t *>(path
.c_str());
169 download_file_data
.dwData
= success
;
171 if (::IsWindow(download_file_caller_window_
)) {
172 ::SendMessage(download_file_caller_window_
, WM_COPYDATA
, NULL
,
173 reinterpret_cast<LPARAM
>(&download_file_data
));
177 // Don't access any members after this.