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 #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/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/file_path.h" | 10 #include "base/file_path.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/weak_ptr.h" |
12 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
13 #include "base/path_service.h" | 14 #include "base/path_service.h" |
14 #include "base/string_util.h" | 15 #include "base/string_util.h" |
15 #include "base/stringprintf.h" | 16 #include "base/stringprintf.h" |
16 #include "base/threading/thread_restrictions.h" | 17 #include "base/threading/thread_restrictions.h" |
| 18 #include "base/threading/worker_pool.h" |
17 #include "build/build_config.h" | 19 #include "build/build_config.h" |
18 #include "chrome/browser/extensions/extension_info_map.h" | 20 #include "chrome/browser/extensions/extension_info_map.h" |
19 #include "chrome/browser/net/chrome_url_request_context.h" | 21 #include "chrome/browser/net/chrome_url_request_context.h" |
20 #include "chrome/common/chrome_paths.h" | 22 #include "chrome/common/chrome_paths.h" |
21 #include "chrome/common/extensions/extension.h" | 23 #include "chrome/common/extensions/extension.h" |
22 #include "chrome/common/extensions/extension_file_util.h" | 24 #include "chrome/common/extensions/extension_file_util.h" |
23 #include "chrome/common/extensions/extension_resource.h" | 25 #include "chrome/common/extensions/extension_resource.h" |
24 #include "chrome/common/url_constants.h" | 26 #include "chrome/common/url_constants.h" |
25 #include "content/public/browser/resource_request_info.h" | 27 #include "content/public/browser/resource_request_info.h" |
26 #include "googleurl/src/url_util.h" | 28 #include "googleurl/src/url_util.h" |
(...skipping 24 matching lines...) Expand all Loading... |
51 } | 53 } |
52 | 54 |
53 if (send_cors_header) { | 55 if (send_cors_header) { |
54 raw_headers.append(1, '\0'); | 56 raw_headers.append(1, '\0'); |
55 raw_headers.append("Access-Control-Allow-Origin: *"); | 57 raw_headers.append("Access-Control-Allow-Origin: *"); |
56 } | 58 } |
57 raw_headers.append(2, '\0'); | 59 raw_headers.append(2, '\0'); |
58 return new net::HttpResponseHeaders(raw_headers); | 60 return new net::HttpResponseHeaders(raw_headers); |
59 } | 61 } |
60 | 62 |
| 63 void ReadMimeTypeFromFile(const FilePath& filename, |
| 64 std::string* mime_type, |
| 65 bool* result) { |
| 66 *result = net::GetMimeTypeFromFile(filename, mime_type); |
| 67 } |
| 68 |
61 class URLRequestResourceBundleJob : public net::URLRequestSimpleJob { | 69 class URLRequestResourceBundleJob : public net::URLRequestSimpleJob { |
62 public: | 70 public: |
63 URLRequestResourceBundleJob( | 71 URLRequestResourceBundleJob( |
64 net::URLRequest* request, const FilePath& filename, int resource_id, | 72 net::URLRequest* request, const FilePath& filename, int resource_id, |
65 const std::string& content_security_policy, bool send_cors_header) | 73 const std::string& content_security_policy, bool send_cors_header) |
66 : net::URLRequestSimpleJob(request), | 74 : net::URLRequestSimpleJob(request), |
67 filename_(filename), | 75 filename_(filename), |
68 resource_id_(resource_id) { | 76 resource_id_(resource_id), |
| 77 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
69 response_info_.headers = BuildHttpHeaders(content_security_policy, | 78 response_info_.headers = BuildHttpHeaders(content_security_policy, |
70 send_cors_header); | 79 send_cors_header); |
71 } | 80 } |
72 | 81 |
73 // Overridden from URLRequestSimpleJob: | 82 // Overridden from URLRequestSimpleJob: |
74 virtual bool GetData(std::string* mime_type, | 83 virtual int GetData(std::string* mime_type, |
75 std::string* charset, | 84 std::string* charset, |
76 std::string* data) const OVERRIDE { | 85 std::string* data, |
| 86 const net::CompletionCallback& callback) const OVERRIDE { |
77 const ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 87 const ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
78 *data = rb.GetRawDataResource( | 88 *data = rb.GetRawDataResource( |
79 resource_id_, ui::SCALE_FACTOR_NONE).as_string(); | 89 resource_id_, ui::SCALE_FACTOR_NONE).as_string(); |
80 | 90 |
81 // Requests should not block on the disk! On Windows this goes to the | 91 std::string* read_mime_type = new std::string; |
82 // registry. | 92 bool* read_result = new bool; |
83 // http://code.google.com/p/chromium/issues/detail?id=59849 | 93 bool posted = base::WorkerPool::PostTaskAndReply( |
84 bool result; | 94 FROM_HERE, |
85 { | 95 base::Bind(&ReadMimeTypeFromFile, filename_, |
86 base::ThreadRestrictions::ScopedAllowIO allow_io; | 96 base::Unretained(read_mime_type), |
87 result = net::GetMimeTypeFromFile(filename_, mime_type); | 97 base::Unretained(read_result)), |
88 } | 98 base::Bind(&URLRequestResourceBundleJob::OnMimeTypeRead, |
| 99 weak_factory_.GetWeakPtr(), |
| 100 mime_type, charset, data, |
| 101 base::Owned(read_mime_type), |
| 102 base::Owned(read_result), |
| 103 callback), |
| 104 true /* task is slow */); |
| 105 DCHECK(posted); |
89 | 106 |
90 if (StartsWithASCII(*mime_type, "text/", false)) { | 107 return net::ERR_IO_PENDING; |
91 // All of our HTML files should be UTF-8 and for other resource types | |
92 // (like images), charset doesn't matter. | |
93 DCHECK(IsStringUTF8(*data)); | |
94 *charset = "utf-8"; | |
95 } | |
96 return result; | |
97 } | 108 } |
98 | 109 |
99 virtual void GetResponseInfo(net::HttpResponseInfo* info) { | 110 virtual void GetResponseInfo(net::HttpResponseInfo* info) { |
100 *info = response_info_; | 111 *info = response_info_; |
101 } | 112 } |
102 | 113 |
103 private: | 114 private: |
104 virtual ~URLRequestResourceBundleJob() { } | 115 virtual ~URLRequestResourceBundleJob() { } |
105 | 116 |
| 117 void OnMimeTypeRead(std::string* out_mime_type, |
| 118 std::string* charset, |
| 119 std::string* data, |
| 120 std::string* read_mime_type, |
| 121 bool* read_result, |
| 122 const net::CompletionCallback& callback) { |
| 123 *out_mime_type = *read_mime_type; |
| 124 if (StartsWithASCII(*read_mime_type, "text/", false)) { |
| 125 // All of our HTML files should be UTF-8 and for other resource types |
| 126 // (like images), charset doesn't matter. |
| 127 DCHECK(IsStringUTF8(*data)); |
| 128 *charset = "utf-8"; |
| 129 } |
| 130 int result = *read_result? net::OK: net::ERR_FAILED; |
| 131 callback.Run(result); |
| 132 } |
| 133 |
106 // We need the filename of the resource to determine the mime type. | 134 // We need the filename of the resource to determine the mime type. |
107 FilePath filename_; | 135 FilePath filename_; |
108 | 136 |
109 // The resource bundle id to load. | 137 // The resource bundle id to load. |
110 int resource_id_; | 138 int resource_id_; |
111 | 139 |
112 net::HttpResponseInfo response_info_; | 140 net::HttpResponseInfo response_info_; |
| 141 |
| 142 mutable base::WeakPtrFactory<URLRequestResourceBundleJob> weak_factory_; |
113 }; | 143 }; |
114 | 144 |
115 class GeneratedBackgroundPageJob : public net::URLRequestSimpleJob { | 145 class GeneratedBackgroundPageJob : public net::URLRequestSimpleJob { |
116 public: | 146 public: |
117 GeneratedBackgroundPageJob(net::URLRequest* request, | 147 GeneratedBackgroundPageJob(net::URLRequest* request, |
118 const scoped_refptr<const Extension> extension, | 148 const scoped_refptr<const Extension> extension, |
119 const std::string& content_security_policy) | 149 const std::string& content_security_policy) |
120 : net::URLRequestSimpleJob(request), | 150 : net::URLRequestSimpleJob(request), |
121 extension_(extension) { | 151 extension_(extension) { |
122 const bool send_cors_headers = false; | 152 const bool send_cors_headers = false; |
123 response_info_.headers = BuildHttpHeaders(content_security_policy, | 153 response_info_.headers = BuildHttpHeaders(content_security_policy, |
124 send_cors_headers); | 154 send_cors_headers); |
125 } | 155 } |
126 | 156 |
127 // Overridden from URLRequestSimpleJob: | 157 // Overridden from URLRequestSimpleJob: |
128 virtual bool GetData(std::string* mime_type, | 158 virtual int GetData(std::string* mime_type, |
129 std::string* charset, | 159 std::string* charset, |
130 std::string* data) const OVERRIDE { | 160 std::string* data, |
| 161 const net::CompletionCallback& callback) const OVERRIDE { |
131 *mime_type = "text/html"; | 162 *mime_type = "text/html"; |
132 *charset = "utf-8"; | 163 *charset = "utf-8"; |
133 | 164 |
134 *data = "<!DOCTYPE html>\n<body>\n"; | 165 *data = "<!DOCTYPE html>\n<body>\n"; |
135 for (size_t i = 0; i < extension_->background_scripts().size(); ++i) { | 166 for (size_t i = 0; i < extension_->background_scripts().size(); ++i) { |
136 *data += "<script src=\""; | 167 *data += "<script src=\""; |
137 *data += extension_->background_scripts()[i]; | 168 *data += extension_->background_scripts()[i]; |
138 *data += "\"></script>\n"; | 169 *data += "\"></script>\n"; |
139 } | 170 } |
140 | 171 |
141 return true; | 172 return net::OK; |
142 } | 173 } |
143 | 174 |
144 virtual void GetResponseInfo(net::HttpResponseInfo* info) { | 175 virtual void GetResponseInfo(net::HttpResponseInfo* info) { |
145 *info = response_info_; | 176 *info = response_info_; |
146 } | 177 } |
147 | 178 |
148 private: | 179 private: |
149 virtual ~GeneratedBackgroundPageJob() {} | 180 virtual ~GeneratedBackgroundPageJob() {} |
150 | 181 |
151 scoped_refptr<const Extension> extension_; | 182 scoped_refptr<const Extension> extension_; |
152 net::HttpResponseInfo response_info_; | 183 net::HttpResponseInfo response_info_; |
153 }; | 184 }; |
154 | 185 |
| 186 void ReadResourceFilePath(const ExtensionResource& resource, |
| 187 FilePath* file_path) { |
| 188 *file_path = resource.GetFilePath(); |
| 189 } |
| 190 |
155 class URLRequestExtensionJob : public net::URLRequestFileJob { | 191 class URLRequestExtensionJob : public net::URLRequestFileJob { |
156 public: | 192 public: |
157 URLRequestExtensionJob(net::URLRequest* request, | 193 URLRequestExtensionJob(net::URLRequest* request, |
158 const FilePath& filename, | 194 const std::string& extension_id, |
| 195 const FilePath& directory_path, |
159 const std::string& content_security_policy, | 196 const std::string& content_security_policy, |
160 bool send_cors_header) | 197 bool send_cors_header) |
161 : net::URLRequestFileJob(request, filename) { | 198 : net::URLRequestFileJob(request, FilePath()), |
| 199 // TODO(tc): Move all of these files into resources.pak so we don't break |
| 200 // when updating on Linux. |
| 201 resource_(extension_id, directory_path, |
| 202 extension_file_util::ExtensionURLToRelativeFilePath( |
| 203 request->url())), |
| 204 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
162 response_info_.headers = BuildHttpHeaders(content_security_policy, | 205 response_info_.headers = BuildHttpHeaders(content_security_policy, |
163 send_cors_header); | 206 send_cors_header); |
164 } | 207 } |
165 | 208 |
166 virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE { | 209 virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE { |
167 *info = response_info_; | 210 *info = response_info_; |
168 } | 211 } |
169 | 212 |
| 213 virtual void Start() OVERRIDE { |
| 214 FilePath* read_file_path = new FilePath; |
| 215 bool posted = base::WorkerPool::PostTaskAndReply( |
| 216 FROM_HERE, |
| 217 base::Bind(&ReadResourceFilePath, resource_, |
| 218 base::Unretained(read_file_path)), |
| 219 base::Bind(&URLRequestExtensionJob::OnFilePathRead, |
| 220 weak_factory_.GetWeakPtr(), |
| 221 base::Owned(read_file_path)), |
| 222 true /* task is slow */); |
| 223 DCHECK(posted); |
| 224 } |
| 225 |
170 private: | 226 private: |
171 virtual ~URLRequestExtensionJob() {} | 227 virtual ~URLRequestExtensionJob() {} |
172 | 228 |
| 229 void OnFilePathRead(FilePath* read_file_path) { |
| 230 file_path_ = *read_file_path; |
| 231 URLRequestFileJob::Start(); |
| 232 } |
| 233 |
173 net::HttpResponseInfo response_info_; | 234 net::HttpResponseInfo response_info_; |
| 235 ExtensionResource resource_; |
| 236 base::WeakPtrFactory<URLRequestExtensionJob> weak_factory_; |
174 }; | 237 }; |
175 | 238 |
176 bool ExtensionCanLoadInIncognito(const ResourceRequestInfo* info, | 239 bool ExtensionCanLoadInIncognito(const ResourceRequestInfo* info, |
177 const std::string& extension_id, | 240 const std::string& extension_id, |
178 ExtensionInfoMap* extension_info_map) { | 241 ExtensionInfoMap* extension_info_map) { |
179 if (!extension_info_map->IsIncognitoEnabled(extension_id)) | 242 if (!extension_info_map->IsIncognitoEnabled(extension_id)) |
180 return false; | 243 return false; |
181 | 244 |
182 // Only allow incognito toplevel navigations to extension resources in | 245 // Only allow incognito toplevel navigations to extension resources in |
183 // split mode. In spanning mode, the extension must run in a single process, | 246 // split mode. In spanning mode, the extension must run in a single process, |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 FilePath bm_resource_path = | 378 FilePath bm_resource_path = |
316 FilePath().AppendASCII(kComponentExtensionResources[i].name); | 379 FilePath().AppendASCII(kComponentExtensionResources[i].name); |
317 bm_resource_path = bm_resource_path.NormalizePathSeparators(); | 380 bm_resource_path = bm_resource_path.NormalizePathSeparators(); |
318 if (relative_path == bm_resource_path) { | 381 if (relative_path == bm_resource_path) { |
319 return new URLRequestResourceBundleJob(request, relative_path, | 382 return new URLRequestResourceBundleJob(request, relative_path, |
320 kComponentExtensionResources[i].value, content_security_policy, | 383 kComponentExtensionResources[i].value, content_security_policy, |
321 send_cors_header); | 384 send_cors_header); |
322 } | 385 } |
323 } | 386 } |
324 } | 387 } |
325 // TODO(tc): Move all of these files into resources.pak so we don't break | |
326 // when updating on Linux. | |
327 ExtensionResource resource(extension_id, directory_path, | |
328 extension_file_util::ExtensionURLToRelativeFilePath(request->url())); | |
329 | 388 |
330 FilePath resource_file_path; | 389 return new URLRequestExtensionJob(request, extension_id, directory_path, |
331 { | |
332 // Getting the file path will touch the file system. Fixing | |
333 // crbug.com/59849 would also fix this. Suppress the error for now. | |
334 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
335 resource_file_path = resource.GetFilePath(); | |
336 } | |
337 | |
338 return new URLRequestExtensionJob(request, resource_file_path, | |
339 content_security_policy, send_cors_header); | 390 content_security_policy, send_cors_header); |
340 } | 391 } |
341 | 392 |
342 } // namespace | 393 } // namespace |
343 | 394 |
344 net::URLRequestJobFactory::ProtocolHandler* CreateExtensionProtocolHandler( | 395 net::URLRequestJobFactory::ProtocolHandler* CreateExtensionProtocolHandler( |
345 bool is_incognito, | 396 bool is_incognito, |
346 ExtensionInfoMap* extension_info_map) { | 397 ExtensionInfoMap* extension_info_map) { |
347 return new ExtensionProtocolHandler(is_incognito, extension_info_map); | 398 return new ExtensionProtocolHandler(is_incognito, extension_info_map); |
348 } | 399 } |
OLD | NEW |