OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #ifndef CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ | 5 #ifndef CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ |
6 #define CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ | 6 #define CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 | 10 |
11 #include <string> | 11 #include <string> |
12 | 12 |
13 #include "base/files/file.h" | 13 #include "base/files/file.h" |
14 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
15 #include "base/gtest_prod_util.h" | 15 #include "base/gtest_prod_util.h" |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "base/macros.h" | 17 #include "base/macros.h" |
18 #include "base/memory/linked_ptr.h" | 18 #include "base/memory/linked_ptr.h" |
19 #include "base/memory/scoped_ptr.h" | 19 #include "base/memory/scoped_ptr.h" |
20 #include "base/time/time.h" | 20 #include "base/time/time.h" |
21 #include "content/common/content_export.h" | 21 #include "content/common/content_export.h" |
22 #include "content/public/browser/download_interrupt_reasons.h" | 22 #include "content/public/browser/download_interrupt_reasons.h" |
23 #include "crypto/sha2.h" | 23 #include "crypto/secure_hash.h" |
24 #include "net/base/net_errors.h" | 24 #include "net/base/net_errors.h" |
25 #include "net/log/net_log.h" | 25 #include "net/log/net_log.h" |
26 #include "url/gurl.h" | 26 #include "url/gurl.h" |
27 | 27 |
28 namespace crypto { | |
29 class SecureHash; | |
30 } | |
31 | |
32 namespace content { | 28 namespace content { |
33 | 29 |
34 // File being downloaded and saved to disk. This is a base class | 30 // File being downloaded and saved to disk. This is a base class |
35 // for DownloadFile and SaveFile, which keep more state information. | 31 // for DownloadFile and SaveFile, which keep more state information. BaseFile |
| 32 // considers itself the owner of the physical file and will delete it when the |
| 33 // BaseFile object is destroyed unless the ownership is revoked via a call to |
| 34 // Detach(). |
36 class CONTENT_EXPORT BaseFile { | 35 class CONTENT_EXPORT BaseFile { |
37 public: | 36 public: |
38 // May be constructed on any thread. All other routines (including | 37 // May be constructed on any thread. All other routines (including |
39 // destruction) must occur on the FILE thread. | 38 // destruction) must occur on the FILE thread. |
40 BaseFile(const base::FilePath& full_path, | 39 BaseFile(const net::BoundNetLog& bound_net_log); |
41 const GURL& source_url, | 40 ~BaseFile(); |
42 const GURL& referrer_url, | |
43 int64_t received_bytes, | |
44 bool calculate_hash, | |
45 const std::string& hash_state, | |
46 base::File file, | |
47 const net::BoundNetLog& bound_net_log); | |
48 virtual ~BaseFile(); | |
49 | 41 |
50 // Returns DOWNLOAD_INTERRUPT_REASON_NONE on success, or a | 42 // Returns DOWNLOAD_INTERRUPT_REASON_NONE on success, or a |
51 // DownloadInterruptReason on failure. |default_directory| specifies the | 43 // DownloadInterruptReason on failure. Upon success, the file at |full_path()| |
52 // directory to create the temporary file in if |full_path()| is empty. If | 44 // is assumed to be owned by the BaseFile. It will be deleted when the |
53 // |default_directory| and |full_path()| are empty, then a temporary file will | 45 // BaseFile object is destroyed unless Detach() is called before destroying |
54 // be created in the default download location as determined by | 46 // the BaseFile instance. |
55 // ContentBrowserClient. | 47 // |
56 DownloadInterruptReason Initialize(const base::FilePath& default_directory); | 48 // |full_path|: Full path to the download file. Can be empty, in which case |
| 49 // the rules described in |default_directory| will be used to generate a |
| 50 // temporary filename. |
| 51 // |
| 52 // |default_directory|: specifies the directory to create the temporary file |
| 53 // in if |full_path| is empty. If |default_directory| and |full_path| are |
| 54 // empty, then a temporary file will be created in the default download |
| 55 // location as determined by ContentBrowserClient. |
| 56 // |
| 57 // |file|: The base::File handle to use. If specified, BaseFile will not open |
| 58 // a file and will use this handle. The file should be opened for both |
| 59 // read and write. Only makes sense if |full_path| is non-empty since it |
| 60 // implies that the caller already knows the path to the file. There's no |
| 61 // perfect way to come up with a canonical path for a file. So BaseFile |
| 62 // will not attempt to determine the |full_path|. |
| 63 // |
| 64 // |bytes_so_far|: If a file is provided (via |full_path| or |file|), then |
| 65 // this argument specifies the size of the file to expect. It is legal for |
| 66 // the file to be larger, in which case the file will be truncated down to |
| 67 // this size. However, if the file is shorter, then the operation will |
| 68 // fail with DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT. |
| 69 // |
| 70 // |hash_so_far|: If |bytes_so_far| is non-zero, this specifies the SHA-256 |
| 71 // hash of the first |bytes_so_far| bytes of the target file. If |
| 72 // specified, BaseFile will read the first |bytes_so_far| of the target |
| 73 // file in order to calculate the hash and verify that the file matches. |
| 74 // If there's a mismatch, then the operation fails with |
| 75 // DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH. Not used if |hash_state| |
| 76 // is also specified. |
| 77 // |
| 78 // |hash_state|: The partial hash object to use. Only meaningful if there's a |
| 79 // preexisting target file and it is non-empty (i.e. bytes_so_far is |
| 80 // non-zero). If specified, BaseFile will assume that the bytes up to |
| 81 // |bytes_so_far| has been accurately hashed into |hash_state| and will |
| 82 // ignore |hash_so_far|. |
| 83 DownloadInterruptReason Initialize(const base::FilePath& full_path, |
| 84 const base::FilePath& default_directory, |
| 85 base::File file, |
| 86 int64_t bytes_so_far, |
| 87 const std::string& hash_so_far, |
| 88 scoped_ptr<crypto::SecureHash> hash_state); |
57 | 89 |
58 // Write a new chunk of data to the file. Returns a DownloadInterruptReason | 90 // Write a new chunk of data to the file. Returns a DownloadInterruptReason |
59 // indicating the result of the operation. | 91 // indicating the result of the operation. |
60 DownloadInterruptReason AppendDataToFile(const char* data, size_t data_len); | 92 DownloadInterruptReason AppendDataToFile(const char* data, size_t data_len); |
61 | 93 |
62 // Rename the download file. Returns a DownloadInterruptReason indicating the | 94 // Rename the download file. Returns a DownloadInterruptReason indicating the |
63 // result of the operation. A return code of NONE indicates that the rename | 95 // result of the operation. A return code of NONE indicates that the rename |
64 // was successful. After a failure, the full_path() and in_progress() can be | 96 // was successful. After a failure, the full_path() and in_progress() can be |
65 // used to determine the last known filename and whether the file is available | 97 // used to determine the last known filename and whether the file is available |
66 // for writing or retrying the rename. | 98 // for writing or retrying the rename. Call Finish() to obtain the last known |
67 virtual DownloadInterruptReason Rename(const base::FilePath& full_path); | 99 // hash state. |
| 100 DownloadInterruptReason Rename(const base::FilePath& full_path); |
68 | 101 |
69 // Detach the file so it is not deleted on destruction. | 102 // Mark the file as detached. Up until this method is called, BaseFile assumes |
70 virtual void Detach(); | 103 // ownership of the file and hence will delete the file if the BaseFile object |
| 104 // is destroyed. Calling Detach() causes BaseFile to assume that it no longer |
| 105 // owns the file. Detach() can be called at any time. Close() must still be |
| 106 // called to close the file if it is open. |
| 107 void Detach(); |
71 | 108 |
72 // Abort the download and automatically close the file. | 109 // Abort the download and automatically close and delete the file. |
73 void Cancel(); | 110 void Cancel(); |
74 | 111 |
75 // Indicate that the download has finished. No new data will be received. | 112 // Indicate that the download has finished. No new data will be received. |
76 void Finish(); | 113 // Returns the SecureHash object representing the state of the hash function |
77 | 114 // at the end of the operation. |
78 // Indicate that the download is being aborted due to an error. This is | 115 scoped_ptr<crypto::SecureHash> Finish(); |
79 // identical to Finish() with the exception that the hash state will not be | |
80 // finalized. | |
81 void FinishWithError(); | |
82 | |
83 // Set the client guid which will be used to identify the app to the | |
84 // system AV scanning function. Should be called before | |
85 // AnnotateWithSourceInformation() to take effect. | |
86 void SetClientGuid(const std::string& guid); | |
87 | 116 |
88 // Informs the OS that this file came from the internet. Returns a | 117 // Informs the OS that this file came from the internet. Returns a |
89 // DownloadInterruptReason indicating the result of the operation. | 118 // DownloadInterruptReason indicating the result of the operation. |
90 // Note: SetClientGuid() should be called before this function on | 119 // |
91 // Windows to ensure the correct app client ID is available. | 120 // |client_guid|: The client GUID which will be used to identify the caller to |
92 DownloadInterruptReason AnnotateWithSourceInformation(); | 121 // the system AV scanning function. |
| 122 // |
| 123 // |source_url| / |referrer_url|: Source and referrer for the network request |
| 124 // that originated this download. Will be used to annotate source |
| 125 // information and also to determine the relative danger level of the |
| 126 // file. |
| 127 DownloadInterruptReason AnnotateWithSourceInformation( |
| 128 const std::string& client_guid, |
| 129 const GURL& source_url, |
| 130 const GURL& referrer_url); |
93 | 131 |
94 // Returns the last known path to the download file. Can be empty if there's | 132 // Returns the last known path to the download file. Can be empty if there's |
95 // no file. | 133 // no file. |
96 const base::FilePath& full_path() const { return full_path_; } | 134 const base::FilePath& full_path() const { return full_path_; } |
97 | 135 |
98 // Returns true if the file is open. If true, the file can be written to or | 136 // Returns true if the file is open. If true, the file can be written to or |
99 // renamed. | 137 // renamed. |
100 bool in_progress() const { return file_.IsValid(); } | 138 bool in_progress() const { return file_.IsValid(); } |
101 | 139 |
102 // Returns the number of bytes in the file pointed to by full_path(). | 140 // Returns the number of bytes in the file pointed to by full_path(). |
103 int64_t bytes_so_far() const { return bytes_so_far_; } | 141 int64_t bytes_so_far() const { return bytes_so_far_; } |
104 | 142 |
105 // Fills |hash| with the hash digest for the file. | 143 std::string DebugString() const; |
106 // Returns true if digest is successfully calculated. | |
107 virtual bool GetHash(std::string* hash); | |
108 | |
109 // Returns the current (intermediate) state of the hash as a byte string. | |
110 virtual std::string GetHashState(); | |
111 | |
112 // Returns true if the given hash is considered empty. An empty hash is | |
113 // a string of size crypto::kSHA256Length that contains only zeros (initial | |
114 // value for the hash). | |
115 static bool IsEmptyHash(const std::string& hash); | |
116 | |
117 virtual std::string DebugString() const; | |
118 | 144 |
119 private: | 145 private: |
120 friend class BaseFileTest; | 146 friend class BaseFileTest; |
121 FRIEND_TEST_ALL_PREFIXES(BaseFileTest, IsEmptyHash); | 147 FRIEND_TEST_ALL_PREFIXES(BaseFileTest, IsEmptyHash); |
122 | 148 |
123 // Creates and opens the file_ if it is NULL. | 149 // Creates and opens the file_ if it is invalid. |
124 DownloadInterruptReason Open(); | 150 // |
| 151 // If |hash_so_far| is not empty, then it must match the SHA-256 hash of the |
| 152 // first |bytes_so_far_| bytes of |file_|. If there's a hash mismatch, Open() |
| 153 // fails with DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH. |
| 154 // |
| 155 // If the opened file is shorter than |bytes_so_far_| bytes, then Open() fails |
| 156 // with DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT. If the opened file is |
| 157 // longer, then the file is truncated to |bytes_so_far_|. |
| 158 // |
| 159 // Open() can fail for other reasons as well. In that case, it returns a |
| 160 // relevant interrupt reason. Unless Open() return |
| 161 // DOWNLOAD_INTERRUPT_REASON_NONE, it should be assumed that |file_| is not |
| 162 // valid. |
| 163 DownloadInterruptReason Open(const std::string& hash_so_far); |
125 | 164 |
126 // Closes and resets file_. | 165 // Closes and resets file_. |
127 void Close(); | 166 void Close(); |
128 | 167 |
129 // Resets file_. | 168 // Resets file_. |
130 void ClearFile(); | 169 void ClearFile(); |
131 | 170 |
132 // Platform specific method that moves a file to a new path and adjusts the | 171 // Platform specific method that moves a file to a new path and adjusts the |
133 // security descriptor / permissions on the file to match the defaults for the | 172 // security descriptor / permissions on the file to match the defaults for the |
134 // new directory. | 173 // new directory. |
135 DownloadInterruptReason MoveFileAndAdjustPermissions( | 174 DownloadInterruptReason MoveFileAndAdjustPermissions( |
136 const base::FilePath& new_path); | 175 const base::FilePath& new_path); |
137 | 176 |
138 // Split out from CurrentSpeed to enable testing. | 177 // Split out from CurrentSpeed to enable testing. |
139 int64_t CurrentSpeedAtTime(base::TimeTicks current_time) const; | 178 int64_t CurrentSpeedAtTime(base::TimeTicks current_time) const; |
140 | 179 |
| 180 // Verifies that: |
| 181 // * Size of the file represented by |file_| is at least |bytes_so_far_|. |
| 182 // |
| 183 // * If |hash_to_expect| is not empty, then the result of hashing the first |
| 184 // |bytes_so_far_| bytes of |file_| matches |hash_to_expect|. |
| 185 // |
| 186 // If the result is REASON_NONE, then on return |secure_hash_| is valid and |
| 187 // is ready to hash bytes from offset |bytes_so_far_| + 1. |
| 188 DownloadInterruptReason CalculatePartialHash( |
| 189 const std::string& hash_to_expect); |
| 190 |
141 // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |error| and passes error | 191 // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |error| and passes error |
142 // on through, converting to a |DownloadInterruptReason|. | 192 // on through, converting to a |DownloadInterruptReason|. |
143 DownloadInterruptReason LogNetError(const char* operation, net::Error error); | 193 DownloadInterruptReason LogNetError(const char* operation, net::Error error); |
144 | 194 |
145 // Log the system error in |os_error| and converts it into a | 195 // Log the system error in |os_error| and converts it into a |
146 // |DownloadInterruptReason|. | 196 // |DownloadInterruptReason|. |
147 DownloadInterruptReason LogSystemError(const char* operation, | 197 DownloadInterruptReason LogSystemError(const char* operation, |
148 logging::SystemErrorCode os_error); | 198 logging::SystemErrorCode os_error); |
149 | 199 |
150 // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |os_error| and |reason|. | 200 // Log a TYPE_DOWNLOAD_FILE_ERROR NetLog event with |os_error| and |reason|. |
151 // Returns |reason|. | 201 // Returns |reason|. |
152 DownloadInterruptReason LogInterruptReason( | 202 DownloadInterruptReason LogInterruptReason( |
153 const char* operation, int os_error, | 203 const char* operation, int os_error, |
154 DownloadInterruptReason reason); | 204 DownloadInterruptReason reason); |
155 | 205 |
156 static const unsigned char kEmptySha256Hash[crypto::kSHA256Length]; | |
157 | |
158 // Full path to the file including the file name. | 206 // Full path to the file including the file name. |
159 base::FilePath full_path_; | 207 base::FilePath full_path_; |
160 | 208 |
161 // Source URL for the file being downloaded. | |
162 GURL source_url_; | |
163 | |
164 // The URL where the download was initiated. | |
165 GURL referrer_url_; | |
166 | |
167 std::string client_guid_; | |
168 | |
169 // OS file for writing | 209 // OS file for writing |
170 base::File file_; | 210 base::File file_; |
171 | 211 |
172 // Amount of data received up so far, in bytes. | 212 // Amount of data received up so far, in bytes. |
173 int64_t bytes_so_far_; | 213 int64_t bytes_so_far_ = 0; |
| 214 |
| 215 // Used to calculate hash for the file when calculate_hash_ is set. |
| 216 scoped_ptr<crypto::SecureHash> secure_hash_; |
174 | 217 |
175 // Start time for calculating speed. | 218 // Start time for calculating speed. |
176 base::TimeTicks start_tick_; | 219 base::TimeTicks start_tick_; |
177 | 220 |
178 // Indicates if hash should be calculated for the file. | |
179 bool calculate_hash_; | |
180 | |
181 // Used to calculate hash for the file when calculate_hash_ | |
182 // is set. | |
183 scoped_ptr<crypto::SecureHash> secure_hash_; | |
184 | |
185 unsigned char sha256_hash_[crypto::kSHA256Length]; | |
186 | |
187 // Indicates that this class no longer owns the associated file, and so | 221 // Indicates that this class no longer owns the associated file, and so |
188 // won't delete it on destruction. | 222 // won't delete it on destruction. |
189 bool detached_; | 223 bool detached_ = false; |
190 | 224 |
191 net::BoundNetLog bound_net_log_; | 225 net::BoundNetLog bound_net_log_; |
192 | 226 |
193 DISALLOW_COPY_AND_ASSIGN(BaseFile); | 227 DISALLOW_COPY_AND_ASSIGN(BaseFile); |
194 }; | 228 }; |
195 | 229 |
196 } // namespace content | 230 } // namespace content |
197 | 231 |
198 #endif // CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ | 232 #endif // CONTENT_BROWSER_DOWNLOAD_BASE_FILE_H_ |
OLD | NEW |