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

Side by Side Diff: chrome/browser/ui/webui/extensions/extension_icon_source.cc

Issue 11576030: Add size checks to extension icons to prevent out of memory conditions (Closed) Base URL: https://src.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years 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
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/ui/webui/extensions/extension_icon_source.h" 5 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/memory/ref_counted_memory.h" 9 #include "base/memory/ref_counted_memory.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 19 matching lines...) Expand all
30 #include "ui/base/layout.h" 30 #include "ui/base/layout.h"
31 #include "ui/base/resource/resource_bundle.h" 31 #include "ui/base/resource/resource_bundle.h"
32 #include "ui/gfx/codec/png_codec.h" 32 #include "ui/gfx/codec/png_codec.h"
33 #include "ui/gfx/color_utils.h" 33 #include "ui/gfx/color_utils.h"
34 #include "ui/gfx/favicon_size.h" 34 #include "ui/gfx/favicon_size.h"
35 #include "ui/gfx/skbitmap_operations.h" 35 #include "ui/gfx/skbitmap_operations.h"
36 #include "webkit/glue/image_decoder.h" 36 #include "webkit/glue/image_decoder.h"
37 37
38 namespace { 38 namespace {
39 39
40 // Maximum size for the loaded icon. Actual loaded size can be larger than
41 // this because of scaling factor.
42 const int kMaxIconSize = 512;
43
40 scoped_refptr<base::RefCountedMemory> BitmapToMemory(const SkBitmap* image) { 44 scoped_refptr<base::RefCountedMemory> BitmapToMemory(const SkBitmap* image) {
41 base::RefCountedBytes* image_bytes = new base::RefCountedBytes; 45 base::RefCountedBytes* image_bytes = new base::RefCountedBytes;
42 gfx::PNGCodec::EncodeBGRASkBitmap(*image, false, &image_bytes->data()); 46 gfx::PNGCodec::EncodeBGRASkBitmap(*image, false, &image_bytes->data());
43 return image_bytes; 47 return image_bytes;
44 } 48 }
45 49
46 SkBitmap DesaturateImage(const SkBitmap* image) { 50 SkBitmap DesaturateImage(const SkBitmap* image) {
47 color_utils::HSL shift = {-1, 0, 0.6}; 51 color_utils::HSL shift = {-1, 0, 0.6};
48 return SkBitmapOperations::CreateHSLShiftedBitmap(*image, shift); 52 return SkBitmapOperations::CreateHSLShiftedBitmap(*image, shift);
49 } 53 }
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 bool is_incognito, 117 bool is_incognito,
114 int request_id) { 118 int request_id) {
115 // This is where everything gets started. First, parse the request and make 119 // This is where everything gets started. First, parse the request and make
116 // the request data available for later. 120 // the request data available for later.
117 if (!ParseData(path, request_id)) { 121 if (!ParseData(path, request_id)) {
118 SendDefaultResponse(request_id); 122 SendDefaultResponse(request_id);
119 return; 123 return;
120 } 124 }
121 125
122 ExtensionIconRequest* request = GetData(request_id); 126 ExtensionIconRequest* request = GetData(request_id);
127 if (request->size>kMaxIconSize) {
Matt Perry 2012/12/14 18:57:08 Move these ifs below. Also, familiarize yourself
128 request->size = kMaxIconSize;
129 }
123 ExtensionResource icon = 130 ExtensionResource icon =
124 request->extension->GetIconResource(request->size, request->match); 131 request->extension->GetIconResource(request->size, request->match);
125 132
126 if (icon.relative_path().empty()) { 133 if (icon.relative_path().empty()) {
127 LoadIconFailed(request_id); 134 LoadIconFailed(request_id);
128 } else { 135 } else {
129 LoadExtensionImage(icon, request_id); 136 LoadExtensionImage(icon, request_id);
130 } 137 }
131 } 138 }
132 139
(...skipping 26 matching lines...) Expand all
159 else 166 else
160 bitmap = *image; 167 bitmap = *image;
161 168
162 ClearData(request_id); 169 ClearData(request_id);
163 SendResponse(request_id, BitmapToMemory(&bitmap)); 170 SendResponse(request_id, BitmapToMemory(&bitmap));
164 } 171 }
165 172
166 void ExtensionIconSource::LoadDefaultImage(int request_id) { 173 void ExtensionIconSource::LoadDefaultImage(int request_id) {
167 ExtensionIconRequest* request = GetData(request_id); 174 ExtensionIconRequest* request = GetData(request_id);
168 const SkBitmap* default_image = NULL; 175 const SkBitmap* default_image = NULL;
176 if (request->size>kMaxIconSize) {
177 request->size = kMaxIconSize;
178 }
169 179
170 if (request->extension->is_app()) 180 if (request->extension->is_app())
171 default_image = GetDefaultAppImage(); 181 default_image = GetDefaultAppImage();
172 else 182 else
173 default_image = GetDefaultExtensionImage(); 183 default_image = GetDefaultExtensionImage();
174 184
175 SkBitmap resized_image(skia::ImageOperations::Resize( 185 SkBitmap resized_image(skia::ImageOperations::Resize(
176 *default_image, skia::ImageOperations::RESIZE_LANCZOS3, 186 *default_image, skia::ImageOperations::RESIZE_LANCZOS3,
177 request->size, request->size)); 187 request->size, request->size));
178 188
179 // There are cases where Resize returns an empty bitmap, for example if you 189 // There are cases where Resize returns an empty bitmap, for example if you
180 // ask for an image too large. In this case it is better to return the default 190 // ask for an image too large. In this case it is better to return the default
181 // image than returning nothing at all. 191 // image than returning nothing at all.
182 if (resized_image.empty()) 192 if (resized_image.empty())
183 resized_image = *default_image; 193 resized_image = *default_image;
184 194
185 FinalizeImage(&resized_image, request_id); 195 FinalizeImage(&resized_image, request_id);
186 } 196 }
187 197
188 void ExtensionIconSource::LoadExtensionImage(const ExtensionResource& icon, 198 void ExtensionIconSource::LoadExtensionImage(const ExtensionResource& icon,
189 int request_id) { 199 int request_id) {
190 ExtensionIconRequest* request = GetData(request_id); 200 ExtensionIconRequest* request = GetData(request_id);
201 if (request->size>kMaxIconSize) {
202 request->size = kMaxIconSize;
203 }
191 extensions::ImageLoader::Get(profile_)->LoadImageAsync( 204 extensions::ImageLoader::Get(profile_)->LoadImageAsync(
192 request->extension, icon, 205 request->extension, icon,
193 gfx::Size(request->size, request->size), 206 gfx::Size(request->size, request->size),
194 base::Bind(&ExtensionIconSource::OnImageLoaded, this, request_id)); 207 base::Bind(&ExtensionIconSource::OnImageLoaded, this, request_id));
195 } 208 }
196 209
197 void ExtensionIconSource::LoadFaviconImage(int request_id) { 210 void ExtensionIconSource::LoadFaviconImage(int request_id) {
198 FaviconService* favicon_service = 211 FaviconService* favicon_service =
199 FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); 212 FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
200 // Fall back to the default icons if the service isn't available. 213 // Fall back to the default icons if the service isn't available.
201 if (favicon_service == NULL) { 214 if (favicon_service == NULL) {
202 LoadDefaultImage(request_id); 215 LoadDefaultImage(request_id);
203 return; 216 return;
204 } 217 }
205 218
206 GURL favicon_url = GetData(request_id)->extension->GetFullLaunchURL(); 219 GURL favicon_url = GetData(request_id)->extension->GetFullLaunchURL();
207 favicon_service->GetRawFaviconForURL( 220 favicon_service->GetRawFaviconForURL(
208 FaviconService::FaviconForURLParams( 221 FaviconService::FaviconForURLParams(
209 profile_, favicon_url, history::FAVICON, gfx::kFaviconSize), 222 profile_, favicon_url, history::FAVICON, gfx::kFaviconSize),
210 ui::SCALE_FACTOR_100P, 223 ui::SCALE_FACTOR_100P,
211 base::Bind(&ExtensionIconSource::OnFaviconDataAvailable, 224 base::Bind(&ExtensionIconSource::OnFaviconDataAvailable,
212 base::Unretained(this), request_id), 225 base::Unretained(this), request_id),
213 &cancelable_task_tracker_); 226 &cancelable_task_tracker_);
214 } 227 }
215 228
216 void ExtensionIconSource::OnFaviconDataAvailable( 229 void ExtensionIconSource::OnFaviconDataAvailable(
217 int request_id, 230 int request_id,
218 const history::FaviconBitmapResult& bitmap_result) { 231 const history::FaviconBitmapResult& bitmap_result) {
219 ExtensionIconRequest* request = GetData(request_id); 232 ExtensionIconRequest* request = GetData(request_id);
220 233 if (request->size>kMaxIconSize) {
234 request->size = kMaxIconSize;
235 }
221 // Fallback to the default icon if there wasn't a favicon. 236 // Fallback to the default icon if there wasn't a favicon.
222 if (!bitmap_result.is_valid()) { 237 if (!bitmap_result.is_valid()) {
223 LoadDefaultImage(request_id); 238 LoadDefaultImage(request_id);
224 return; 239 return;
225 } 240 }
226 241
227 if (!request->grayscale) { 242 if (!request->grayscale) {
228 // If we don't need a grayscale image, then we can bypass FinalizeImage 243 // If we don't need a grayscale image, then we can bypass FinalizeImage
229 // to avoid unnecessary conversions. 244 // to avoid unnecessary conversions.
230 ClearData(request_id); 245 ClearData(request_id);
231 SendResponse(request_id, bitmap_result.bitmap_data); 246 SendResponse(request_id, bitmap_result.bitmap_data);
232 } else { 247 } else {
233 FinalizeImage(ToBitmap(bitmap_result.bitmap_data->front(), 248 FinalizeImage(ToBitmap(bitmap_result.bitmap_data->front(),
234 bitmap_result.bitmap_data->size()), request_id); 249 bitmap_result.bitmap_data->size()), request_id);
235 } 250 }
236 } 251 }
237 252
238 void ExtensionIconSource::OnImageLoaded(int request_id, 253 void ExtensionIconSource::OnImageLoaded(int request_id,
239 const gfx::Image& image) { 254 const gfx::Image& image) {
240 if (image.IsEmpty()) 255 if (image.IsEmpty())
241 LoadIconFailed(request_id); 256 LoadIconFailed(request_id);
242 else 257 else
243 FinalizeImage(image.ToSkBitmap(), request_id); 258 FinalizeImage(image.ToSkBitmap(), request_id);
244 } 259 }
245 260
246 void ExtensionIconSource::LoadIconFailed(int request_id) { 261 void ExtensionIconSource::LoadIconFailed(int request_id) {
247 ExtensionIconRequest* request = GetData(request_id); 262 ExtensionIconRequest* request = GetData(request_id);
263 if (request->size>kMaxIconSize) {
264 request->size = kMaxIconSize;
265 }
248 ExtensionResource icon = 266 ExtensionResource icon =
249 request->extension->GetIconResource(request->size, request->match); 267 request->extension->GetIconResource(request->size, request->match);
250 268
251 if (request->size == extension_misc::EXTENSION_ICON_BITTY) 269 if (request->size == extension_misc::EXTENSION_ICON_BITTY)
252 LoadFaviconImage(request_id); 270 LoadFaviconImage(request_id);
253 else 271 else
254 LoadDefaultImage(request_id); 272 LoadDefaultImage(request_id);
255 } 273 }
256 274
257 bool ExtensionIconSource::ParseData(const std::string& path, 275 bool ExtensionIconSource::ParseData(const std::string& path,
258 int request_id) { 276 int request_id) {
259 // Extract the parameters from the path by lower casing and splitting. 277 // Extract the parameters from the path by lower casing and splitting.
260 std::string path_lower = StringToLowerASCII(path); 278 std::string path_lower = StringToLowerASCII(path);
261 std::vector<std::string> path_parts; 279 std::vector<std::string> path_parts;
262 280
263 base::SplitString(path_lower, '/', &path_parts); 281 base::SplitString(path_lower, '/', &path_parts);
264 if (path_lower.empty() || path_parts.size() < 3) 282 if (path_lower.empty() || path_parts.size() < 3)
265 return false; 283 return false;
266 284
267 std::string size_param = path_parts.at(1); 285 std::string size_param = path_parts.at(1);
268 std::string match_param = path_parts.at(2); 286 std::string match_param = path_parts.at(2);
269 match_param = match_param.substr(0, match_param.find('?')); 287 match_param = match_param.substr(0, match_param.find('?'));
270 288
271 int size; 289 int size;
272 if (!base::StringToInt(size_param, &size)) 290 if (!base::StringToInt(size_param, &size))
273 return false; 291 return false;
274 if (size <= 0) 292 if (size <= 0)
275 return false; 293 return false;
Matt Perry 2012/12/14 18:57:08 This is where the size is parsed. Just move all th
276 294
277 ExtensionIconSet::MatchType match_type; 295 ExtensionIconSet::MatchType match_type;
278 int match_num; 296 int match_num;
279 if (!base::StringToInt(match_param, &match_num)) 297 if (!base::StringToInt(match_param, &match_num))
280 return false; 298 return false;
281 match_type = static_cast<ExtensionIconSet::MatchType>(match_num); 299 match_type = static_cast<ExtensionIconSet::MatchType>(match_num);
282 if (!(match_type == ExtensionIconSet::MATCH_EXACTLY || 300 if (!(match_type == ExtensionIconSet::MATCH_EXACTLY ||
283 match_type == ExtensionIconSet::MATCH_SMALLER || 301 match_type == ExtensionIconSet::MATCH_SMALLER ||
284 match_type == ExtensionIconSet::MATCH_BIGGER)) 302 match_type == ExtensionIconSet::MATCH_BIGGER))
285 match_type = ExtensionIconSet::MATCH_EXACTLY; 303 match_type = ExtensionIconSet::MATCH_EXACTLY;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 344
327 void ExtensionIconSource::ClearData(int request_id) { 345 void ExtensionIconSource::ClearData(int request_id) {
328 std::map<int, ExtensionIconRequest*>::iterator i = 346 std::map<int, ExtensionIconRequest*>::iterator i =
329 request_map_.find(request_id); 347 request_map_.find(request_id);
330 if (i == request_map_.end()) 348 if (i == request_map_.end())
331 return; 349 return;
332 350
333 delete i->second; 351 delete i->second;
334 request_map_.erase(i); 352 request_map_.erase(i);
335 } 353 }
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/ui/webui/favicon_source.cc » ('j') | chrome/browser/ui/webui/favicon_source.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698