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

Side by Side Diff: net/base/mime_sniffer.cc

Issue 12703012: Have media gallery (through native media file util) use MIME sniffer (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments about MIME sniffer. Created 7 years, 7 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
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 // Detecting mime types is a tricky business because we need to balance 5 // Detecting mime types is a tricky business because we need to balance
6 // compatibility concerns with security issues. Here is a survey of how other 6 // compatibility concerns with security issues. Here is a survey of how other
7 // browsers behave and then a description of how we intend to behave. 7 // browsers behave and then a description of how we intend to behave.
8 // 8 //
9 // HTML payload, no Content-Type header: 9 // HTML payload, no Content-Type header:
10 // * IE 7: Render as HTML 10 // * IE 7: Render as HTML
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 107
108 // The number of content bytes we need to use all our magic numbers. Feel free 108 // The number of content bytes we need to use all our magic numbers. Feel free
109 // to increase this number if you add a longer magic number. 109 // to increase this number if you add a longer magic number.
110 static const size_t kBytesRequiredForMagic = 42; 110 static const size_t kBytesRequiredForMagic = 42;
111 111
112 struct MagicNumber { 112 struct MagicNumber {
113 const char* mime_type; 113 const char* mime_type;
114 const char* magic; 114 const char* magic;
115 size_t magic_len; 115 size_t magic_len;
116 bool is_string; 116 bool is_string;
117 const char* mask; // must have same length as |magic|
117 }; 118 };
118 119
119 #define MAGIC_NUMBER(mime_type, magic) \ 120 #define MAGIC_NUMBER(mime_type, magic) \
120 { (mime_type), (magic), sizeof(magic)-1, false }, 121 { (mime_type), (magic), sizeof(magic)-1, false, NULL },
122
123 #define MAGIC_MASK(mime_type, magic, mask) \
124 { (mime_type), (magic), sizeof(magic)-1, false, (mask) },
121 125
122 // Magic strings are case insensitive and must not include '\0' characters 126 // Magic strings are case insensitive and must not include '\0' characters
123 #define MAGIC_STRING(mime_type, magic) \ 127 #define MAGIC_STRING(mime_type, magic) \
124 { (mime_type), (magic), sizeof(magic)-1, true }, 128 { (mime_type), (magic), sizeof(magic)-1, true, NULL },
125 129
126 static const MagicNumber kMagicNumbers[] = { 130 static const MagicNumber kMagicNumbers[] = {
127 // Source: HTML 5 specification 131 // Source: HTML 5 specification
128 MAGIC_NUMBER("application/pdf", "%PDF-") 132 MAGIC_NUMBER("application/pdf", "%PDF-")
129 MAGIC_NUMBER("application/postscript", "%!PS-Adobe-") 133 MAGIC_NUMBER("application/postscript", "%!PS-Adobe-")
130 MAGIC_NUMBER("image/gif", "GIF87a") 134 MAGIC_NUMBER("image/gif", "GIF87a")
131 MAGIC_NUMBER("image/gif", "GIF89a") 135 MAGIC_NUMBER("image/gif", "GIF89a")
132 MAGIC_NUMBER("image/png", "\x89" "PNG\x0D\x0A\x1A\x0A") 136 MAGIC_NUMBER("image/png", "\x89" "PNG\x0D\x0A\x1A\x0A")
133 MAGIC_NUMBER("image/jpeg", "\xFF\xD8\xFF") 137 MAGIC_NUMBER("image/jpeg", "\xFF\xD8\xFF")
134 MAGIC_NUMBER("image/bmp", "BM") 138 MAGIC_NUMBER("image/bmp", "BM")
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 // 173 //
170 // Cons: 174 // Cons:
171 // * These patterns are fairly weak 175 // * These patterns are fairly weak
172 // * If we mistakenly decide something is Flash, we will execute it 176 // * If we mistakenly decide something is Flash, we will execute it
173 // in the origin of an unsuspecting site. This could be a security 177 // in the origin of an unsuspecting site. This could be a security
174 // vulnerability if the site allows users to upload content. 178 // vulnerability if the site allows users to upload content.
175 // 179 //
176 // On balance, we do not include these patterns. 180 // On balance, we do not include these patterns.
177 }; 181 };
178 182
183 static const MagicNumber kExtraMagicNumbers[] = {
184 MAGIC_NUMBER("image/x-xbitmap", "#define")
185 MAGIC_NUMBER("image/x-icon", "\x00\x00\x01\x00")
186 MAGIC_NUMBER("image/svg+xml", "<?xml_version=")
187 MAGIC_NUMBER("audio/wav", "RIFF....WAVEfmt ")
188 MAGIC_NUMBER("video/avi", "RIFF....AVI LIST")
189 MAGIC_NUMBER("video/x-ms-wmv", "RIFF....AVI LIST")
190 MAGIC_NUMBER("audio/ogg", "OggS")
191 MAGIC_MASK("video/mpeg", "\x00\x00\x01\xB0", "\xFF\xFF\xFF\xF0")
192 MAGIC_MASK("audio/mpeg", "\xFF\xE0", "\xFF\xE0")
193 MAGIC_NUMBER("video/3gpp", "....ftyp3g")
194 MAGIC_NUMBER("video/3gpp", "....ftypavcl")
195 MAGIC_NUMBER("video/mp4", "....ftyp")
196 MAGIC_NUMBER("video/quicktime", "MOVI")
197 MAGIC_NUMBER("application/x-shockwave-flash", "CWS")
198 MAGIC_NUMBER("application/x-shockwave-flash", "FWS")
199 MAGIC_NUMBER("video/x-flv", "FLV")
200 };
201
179 // Our HTML sniffer differs slightly from Mozilla. For example, Mozilla will 202 // Our HTML sniffer differs slightly from Mozilla. For example, Mozilla will
180 // decide that a document that begins "<!DOCTYPE SOAP-ENV:Envelope PUBLIC " is 203 // decide that a document that begins "<!DOCTYPE SOAP-ENV:Envelope PUBLIC " is
181 // HTML, but we will not. 204 // HTML, but we will not.
182 205
183 #define MAGIC_HTML_TAG(tag) \ 206 #define MAGIC_HTML_TAG(tag) \
184 MAGIC_STRING("text/html", "<" tag) 207 MAGIC_STRING("text/html", "<" tag)
185 208
186 static const MagicNumber kSniffableTags[] = { 209 static const MagicNumber kSniffableTags[] = {
187 // XML processing directive. Although this is not an HTML mime type, we sniff 210 // XML processing directive. Although this is not an HTML mime type, we sniff
188 // for this in the HTML phase because text/xml is just as powerful as HTML and 211 // for this in the HTML phase because text/xml is just as powerful as HTML and
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 while (len) { 246 while (len) {
224 if ((*magic_entry != '.') && (*magic_entry != *content)) 247 if ((*magic_entry != '.') && (*magic_entry != *content))
225 return false; 248 return false;
226 ++magic_entry; 249 ++magic_entry;
227 ++content; 250 ++content;
228 --len; 251 --len;
229 } 252 }
230 return true; 253 return true;
231 } 254 }
232 255
256 // Like MagicCmp() except that it ANDs each byte with a mask before
257 // the comparison, because there are some bits we don't care about.
258 static bool MagicMaskCmp(const char* magic_entry, const char* content,
259 size_t len, const char* mask) {
260 while (len) {
261 if ((*magic_entry != '.') && (*magic_entry != (*mask & *content)))
262 return false;
263 ++magic_entry;
264 ++content;
265 ++mask;
266 --len;
267 }
268 return true;
269 }
270
233 static bool MatchMagicNumber(const char* content, size_t size, 271 static bool MatchMagicNumber(const char* content, size_t size,
234 const MagicNumber* magic_entry, 272 const MagicNumber* magic_entry,
235 std::string* result) { 273 std::string* result) {
236 const size_t len = magic_entry->magic_len; 274 const size_t len = magic_entry->magic_len;
237 275
238 // Keep kBytesRequiredForMagic honest. 276 // Keep kBytesRequiredForMagic honest.
239 DCHECK_LE(len, kBytesRequiredForMagic); 277 DCHECK_LE(len, kBytesRequiredForMagic);
240 278
241 // To compare with magic strings, we need to compute strlen(content), but 279 // To compare with magic strings, we need to compute strlen(content), but
242 // content might not actually have a null terminator. In that case, we 280 // content might not actually have a null terminator. In that case, we
243 // pretend the length is content_size. 281 // pretend the length is content_size.
244 const char* end = 282 const char* end =
245 static_cast<const char*>(memchr(content, '\0', size)); 283 static_cast<const char*>(memchr(content, '\0', size));
246 const size_t content_strlen = 284 const size_t content_strlen =
247 (end != NULL) ? static_cast<size_t>(end - content) : size; 285 (end != NULL) ? static_cast<size_t>(end - content) : size;
248 286
249 bool match = false; 287 bool match = false;
250 if (magic_entry->is_string) { 288 if (magic_entry->is_string) {
251 if (content_strlen >= len) { 289 if (content_strlen >= len) {
252 // String comparisons are case-insensitive 290 // String comparisons are case-insensitive
253 match = (base::strncasecmp(magic_entry->magic, content, len) == 0); 291 match = (base::strncasecmp(magic_entry->magic, content, len) == 0);
254 } 292 }
255 } else { 293 } else {
256 if (size >= len) 294 if (size >= len) {
257 match = MagicCmp(magic_entry->magic, content, len); 295 if (!magic_entry->mask) {
296 match = MagicCmp(magic_entry->magic, content, len);
297 } else {
298 match = MagicMaskCmp(magic_entry->magic, content, len,
299 magic_entry->mask);
300 }
301 }
258 } 302 }
259 303
260 if (match) { 304 if (match) {
261 result->assign(magic_entry->mime_type); 305 result->assign(magic_entry->mime_type);
262 return true; 306 return true;
263 } 307 }
264 return false; 308 return false;
265 } 309 }
266 310
267 static bool CheckForMagicNumbers(const char* content, size_t size, 311 static bool CheckForMagicNumbers(const char* content, size_t size,
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
679 723
680 // Now we look in our large table of magic numbers to see if we can find 724 // Now we look in our large table of magic numbers to see if we can find
681 // anything that matches the content. 725 // anything that matches the content.
682 if (SniffForMagicNumbers(content, content_size, 726 if (SniffForMagicNumbers(content, content_size,
683 &have_enough_content, result)) 727 &have_enough_content, result))
684 return true; // We've matched a magic number. No more content needed. 728 return true; // We've matched a magic number. No more content needed.
685 729
686 return have_enough_content; 730 return have_enough_content;
687 } 731 }
688 732
733 bool IdentifyExtraMimeType(const char* content, size_t size,
734 std::string* result) {
735 // First check the extra table.
736 if (CheckForMagicNumbers(content, size, kExtraMagicNumbers,
737 sizeof(kExtraMagicNumbers) / sizeof(MagicNumber),
738 NULL, result))
739 return true;
740 // Finally check the original table.
741 return CheckForMagicNumbers(content, size, kMagicNumbers,
742 sizeof(kMagicNumbers) / sizeof(MagicNumber),
743 NULL, result);
744 }
745
689 } // namespace net 746 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698