Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(206)

Side by Side Diff: chrome/browser/extensions/extension_protocols.cc

Issue 15963003: Generate an etag for chrome-extension:// file requests, so caching can be optional (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ToInternalValue Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/browser/extensions/extension_protocols_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #include "chrome/browser/extensions/extension_protocols.h" 5 #include "chrome/browser/extensions/extension_protocols.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/base64.h"
9 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/file_util.h"
10 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
13 #include "base/format_macros.h"
11 #include "base/logging.h" 14 #include "base/logging.h"
12 #include "base/memory/weak_ptr.h" 15 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop.h" 16 #include "base/message_loop.h"
14 #include "base/path_service.h" 17 #include "base/path_service.h"
18 #include "base/sha1.h"
15 #include "base/string_util.h" 19 #include "base/string_util.h"
16 #include "base/stringprintf.h" 20 #include "base/stringprintf.h"
17 #include "base/threading/thread_restrictions.h" 21 #include "base/threading/thread_restrictions.h"
18 #include "base/threading/worker_pool.h" 22 #include "base/threading/worker_pool.h"
19 #include "base/utf_string_conversions.h" 23 #include "base/utf_string_conversions.h"
20 #include "build/build_config.h" 24 #include "build/build_config.h"
21 #include "chrome/browser/extensions/extension_info_map.h" 25 #include "chrome/browser/extensions/extension_info_map.h"
22 #include "chrome/browser/extensions/image_loader.h" 26 #include "chrome/browser/extensions/image_loader.h"
23 #include "chrome/common/chrome_paths.h" 27 #include "chrome/common/chrome_paths.h"
24 #include "chrome/common/extensions/background_info.h" 28 #include "chrome/common/extensions/background_info.h"
(...skipping 20 matching lines...) Expand all
45 #include "net/url_request/url_request_simple_job.h" 49 #include "net/url_request/url_request_simple_job.h"
46 #include "ui/base/resource/resource_bundle.h" 50 #include "ui/base/resource/resource_bundle.h"
47 51
48 using content::ResourceRequestInfo; 52 using content::ResourceRequestInfo;
49 using extensions::Extension; 53 using extensions::Extension;
50 using extensions::SharedModuleInfo; 54 using extensions::SharedModuleInfo;
51 55
52 namespace { 56 namespace {
53 57
54 net::HttpResponseHeaders* BuildHttpHeaders( 58 net::HttpResponseHeaders* BuildHttpHeaders(
55 const std::string& content_security_policy, bool send_cors_header) { 59 const std::string& content_security_policy, bool send_cors_header,
60 const base::Time& last_modified_time) {
56 std::string raw_headers; 61 std::string raw_headers;
57 raw_headers.append("HTTP/1.1 200 OK"); 62 raw_headers.append("HTTP/1.1 200 OK");
58 if (!content_security_policy.empty()) { 63 if (!content_security_policy.empty()) {
59 raw_headers.append(1, '\0'); 64 raw_headers.append(1, '\0');
60 raw_headers.append("Content-Security-Policy: "); 65 raw_headers.append("Content-Security-Policy: ");
61 raw_headers.append(content_security_policy); 66 raw_headers.append(content_security_policy);
62 } 67 }
63 68
64 if (send_cors_header) { 69 if (send_cors_header) {
65 raw_headers.append(1, '\0'); 70 raw_headers.append(1, '\0');
66 raw_headers.append("Access-Control-Allow-Origin: *"); 71 raw_headers.append("Access-Control-Allow-Origin: *");
67 } 72 }
73
74 if (!last_modified_time.is_null()) {
75 // Hash the time and make an etag to avoid exposing the exact
76 // user installation time of the extension.
77 std::string hash = base::StringPrintf("%"PRId64"",
78 last_modified_time.ToInternalValue());
79 hash = base::SHA1HashString(hash);
80 std::string etag;
81 if (base::Base64Encode(hash, &etag)) {
82 raw_headers.append(1, '\0');
83 raw_headers.append("ETag: \"");
84 raw_headers.append(etag);
85 raw_headers.append("\"");
86 // Also force revalidation.
87 raw_headers.append(1, '\0');
88 raw_headers.append("cache-control: no-cache");
89 }
90 }
91
68 raw_headers.append(2, '\0'); 92 raw_headers.append(2, '\0');
69 return new net::HttpResponseHeaders(raw_headers); 93 return new net::HttpResponseHeaders(raw_headers);
70 } 94 }
71 95
72 void ReadMimeTypeFromFile(const base::FilePath& filename, 96 void ReadMimeTypeFromFile(const base::FilePath& filename,
73 std::string* mime_type, 97 std::string* mime_type,
74 bool* result) { 98 bool* result) {
75 *result = net::GetMimeTypeFromFile(filename, mime_type); 99 *result = net::GetMimeTypeFromFile(filename, mime_type);
76 } 100 }
77 101
102 void GetLastModifiedTime(const base::FilePath& filename,
103 base::Time* last_modified_time) {
104 if (file_util::PathExists(filename)) {
105 base::PlatformFileInfo info;
106 if (file_util::GetFileInfo(filename, &info))
107 *last_modified_time = info.last_modified;
108 }
109 }
110
78 class URLRequestResourceBundleJob : public net::URLRequestSimpleJob { 111 class URLRequestResourceBundleJob : public net::URLRequestSimpleJob {
79 public: 112 public:
80 URLRequestResourceBundleJob(net::URLRequest* request, 113 URLRequestResourceBundleJob(net::URLRequest* request,
81 net::NetworkDelegate* network_delegate, 114 net::NetworkDelegate* network_delegate,
82 const base::FilePath& filename, 115 const base::FilePath& filename,
83 int resource_id, 116 int resource_id,
84 const std::string& content_security_policy, 117 const std::string& content_security_policy,
85 bool send_cors_header) 118 bool send_cors_header)
86 : net::URLRequestSimpleJob(request, network_delegate), 119 : net::URLRequestSimpleJob(request, network_delegate),
87 filename_(filename), 120 filename_(filename),
88 resource_id_(resource_id), 121 resource_id_(resource_id),
89 weak_factory_(this) { 122 weak_factory_(this) {
123 // Leave cache headers out of resource bundle requests.
90 response_info_.headers = BuildHttpHeaders(content_security_policy, 124 response_info_.headers = BuildHttpHeaders(content_security_policy,
91 send_cors_header); 125 send_cors_header,
126 base::Time());
92 } 127 }
93 128
94 // Overridden from URLRequestSimpleJob: 129 // Overridden from URLRequestSimpleJob:
95 virtual int GetData(std::string* mime_type, 130 virtual int GetData(std::string* mime_type,
96 std::string* charset, 131 std::string* charset,
97 std::string* data, 132 std::string* data,
98 const net::CompletionCallback& callback) const OVERRIDE { 133 const net::CompletionCallback& callback) const OVERRIDE {
99 const ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 134 const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
100 *data = rb.GetRawDataResource(resource_id_).as_string(); 135 *data = rb.GetRawDataResource(resource_id_).as_string();
101 136
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 190
156 class GeneratedBackgroundPageJob : public net::URLRequestSimpleJob { 191 class GeneratedBackgroundPageJob : public net::URLRequestSimpleJob {
157 public: 192 public:
158 GeneratedBackgroundPageJob(net::URLRequest* request, 193 GeneratedBackgroundPageJob(net::URLRequest* request,
159 net::NetworkDelegate* network_delegate, 194 net::NetworkDelegate* network_delegate,
160 const scoped_refptr<const Extension> extension, 195 const scoped_refptr<const Extension> extension,
161 const std::string& content_security_policy) 196 const std::string& content_security_policy)
162 : net::URLRequestSimpleJob(request, network_delegate), 197 : net::URLRequestSimpleJob(request, network_delegate),
163 extension_(extension) { 198 extension_(extension) {
164 const bool send_cors_headers = false; 199 const bool send_cors_headers = false;
200 // Leave cache headers out of generated background page jobs.
165 response_info_.headers = BuildHttpHeaders(content_security_policy, 201 response_info_.headers = BuildHttpHeaders(content_security_policy,
166 send_cors_headers); 202 send_cors_headers,
203 base::Time());
167 } 204 }
168 205
169 // Overridden from URLRequestSimpleJob: 206 // Overridden from URLRequestSimpleJob:
170 virtual int GetData(std::string* mime_type, 207 virtual int GetData(std::string* mime_type,
171 std::string* charset, 208 std::string* charset,
172 std::string* data, 209 std::string* data,
173 const net::CompletionCallback& callback) const OVERRIDE { 210 const net::CompletionCallback& callback) const OVERRIDE {
174 *mime_type = "text/html"; 211 *mime_type = "text/html";
175 *charset = "utf-8"; 212 *charset = "utf-8";
176 213
(...skipping 13 matching lines...) Expand all
190 *info = response_info_; 227 *info = response_info_;
191 } 228 }
192 229
193 private: 230 private:
194 virtual ~GeneratedBackgroundPageJob() {} 231 virtual ~GeneratedBackgroundPageJob() {}
195 232
196 scoped_refptr<const Extension> extension_; 233 scoped_refptr<const Extension> extension_;
197 net::HttpResponseInfo response_info_; 234 net::HttpResponseInfo response_info_;
198 }; 235 };
199 236
200 void ReadResourceFilePath(const extensions::ExtensionResource& resource, 237 void ReadResourceFilePathAndLastModifiedTime(
201 base::FilePath* file_path) { 238 const extensions::ExtensionResource& resource,
239 base::FilePath* file_path,
240 base::Time* last_modified_time) {
202 *file_path = resource.GetFilePath(); 241 *file_path = resource.GetFilePath();
242 GetLastModifiedTime(*file_path, last_modified_time);
203 } 243 }
204 244
205 class URLRequestExtensionJob : public net::URLRequestFileJob { 245 class URLRequestExtensionJob : public net::URLRequestFileJob {
206 public: 246 public:
207 URLRequestExtensionJob(net::URLRequest* request, 247 URLRequestExtensionJob(net::URLRequest* request,
208 net::NetworkDelegate* network_delegate, 248 net::NetworkDelegate* network_delegate,
209 const std::string& extension_id, 249 const std::string& extension_id,
210 const base::FilePath& directory_path, 250 const base::FilePath& directory_path,
211 const base::FilePath& relative_path, 251 const base::FilePath& relative_path,
212 const std::string& content_security_policy, 252 const std::string& content_security_policy,
213 bool send_cors_header) 253 bool send_cors_header)
214 : net::URLRequestFileJob(request, network_delegate, base::FilePath()), 254 : net::URLRequestFileJob(request, network_delegate, base::FilePath()),
215 // TODO(tc): Move all of these files into resources.pak so we don't break 255 // TODO(tc): Move all of these files into resources.pak so we don't break
216 // when updating on Linux. 256 // when updating on Linux.
217 resource_(extension_id, directory_path, relative_path), 257 resource_(extension_id, directory_path, relative_path),
258 content_security_policy_(content_security_policy),
259 send_cors_header_(send_cors_header),
218 weak_factory_(this) { 260 weak_factory_(this) {
219 response_info_.headers = BuildHttpHeaders(content_security_policy,
220 send_cors_header);
221 } 261 }
222 262
223 virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE { 263 virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE {
224 *info = response_info_; 264 *info = response_info_;
225 } 265 }
226 266
227 virtual void Start() OVERRIDE { 267 virtual void Start() OVERRIDE {
228 base::FilePath* read_file_path = new base::FilePath; 268 base::FilePath* read_file_path = new base::FilePath;
269 base::Time* last_modified_time = new base::Time();
229 bool posted = base::WorkerPool::PostTaskAndReply( 270 bool posted = base::WorkerPool::PostTaskAndReply(
230 FROM_HERE, 271 FROM_HERE,
231 base::Bind(&ReadResourceFilePath, resource_, 272 base::Bind(&ReadResourceFilePathAndLastModifiedTime, resource_,
232 base::Unretained(read_file_path)), 273 base::Unretained(read_file_path),
233 base::Bind(&URLRequestExtensionJob::OnFilePathRead, 274 base::Unretained(last_modified_time)),
275 base::Bind(&URLRequestExtensionJob::OnFilePathAndLastModifiedTimeRead,
234 weak_factory_.GetWeakPtr(), 276 weak_factory_.GetWeakPtr(),
235 base::Owned(read_file_path)), 277 base::Owned(read_file_path),
278 base::Owned(last_modified_time)),
236 true /* task is slow */); 279 true /* task is slow */);
237 DCHECK(posted); 280 DCHECK(posted);
238 } 281 }
239 282
240 private: 283 private:
241 virtual ~URLRequestExtensionJob() {} 284 virtual ~URLRequestExtensionJob() {}
242 285
243 void OnFilePathRead(base::FilePath* read_file_path) { 286 void OnFilePathAndLastModifiedTimeRead(base::FilePath* read_file_path,
287 base::Time* last_modified_time) {
244 file_path_ = *read_file_path; 288 file_path_ = *read_file_path;
289 response_info_.headers = BuildHttpHeaders(
290 content_security_policy_,
291 send_cors_header_,
292 *last_modified_time);
245 URLRequestFileJob::Start(); 293 URLRequestFileJob::Start();
246 } 294 }
247 295
248 net::HttpResponseInfo response_info_; 296 net::HttpResponseInfo response_info_;
249 extensions::ExtensionResource resource_; 297 extensions::ExtensionResource resource_;
298 std::string content_security_policy_;
299 bool send_cors_header_;
250 base::WeakPtrFactory<URLRequestExtensionJob> weak_factory_; 300 base::WeakPtrFactory<URLRequestExtensionJob> weak_factory_;
251 }; 301 };
252 302
253 bool ExtensionCanLoadInIncognito(const ResourceRequestInfo* info, 303 bool ExtensionCanLoadInIncognito(const ResourceRequestInfo* info,
254 const std::string& extension_id, 304 const std::string& extension_id,
255 ExtensionInfoMap* extension_info_map) { 305 ExtensionInfoMap* extension_info_map) {
256 if (!extension_info_map->IsIncognitoEnabled(extension_id)) 306 if (!extension_info_map->IsIncognitoEnabled(extension_id))
257 return false; 307 return false;
258 308
259 // Only allow incognito toplevel navigations to extension resources in 309 // Only allow incognito toplevel navigations to extension resources in
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 send_cors_header); 566 send_cors_header);
517 } 567 }
518 568
519 } // namespace 569 } // namespace
520 570
521 net::URLRequestJobFactory::ProtocolHandler* CreateExtensionProtocolHandler( 571 net::URLRequestJobFactory::ProtocolHandler* CreateExtensionProtocolHandler(
522 bool is_incognito, 572 bool is_incognito,
523 ExtensionInfoMap* extension_info_map) { 573 ExtensionInfoMap* extension_info_map) {
524 return new ExtensionProtocolHandler(is_incognito, extension_info_map); 574 return new ExtensionProtocolHandler(is_incognito, extension_info_map);
525 } 575 }
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/extensions/extension_protocols_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698