| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 | 92 |
| 93 #include "net/base/mime_sniffer.h" | 93 #include "net/base/mime_sniffer.h" |
| 94 | 94 |
| 95 #include "base/basictypes.h" | 95 #include "base/basictypes.h" |
| 96 #include "base/histogram.h" | 96 #include "base/histogram.h" |
| 97 #include "base/logging.h" | 97 #include "base/logging.h" |
| 98 #include "base/string_util.h" | 98 #include "base/string_util.h" |
| 99 #include "googleurl/src/gurl.h" | 99 #include "googleurl/src/gurl.h" |
| 100 #include "net/base/mime_util.h" | 100 #include "net/base/mime_util.h" |
| 101 | 101 |
| 102 namespace { | |
| 103 | |
| 104 class SnifferHistogram : public LinearHistogram { | |
| 105 public: | |
| 106 SnifferHistogram(const char* name, int array_size) | |
| 107 : LinearHistogram(name, 0, array_size - 1, array_size) { | |
| 108 SetFlags(kUmaTargetedHistogramFlag); | |
| 109 } | |
| 110 }; | |
| 111 | |
| 112 } // namespace | |
| 113 | |
| 114 namespace net { | 102 namespace net { |
| 115 | 103 |
| 116 // We aren't interested in looking at more than 512 bytes of content | 104 // We aren't interested in looking at more than 512 bytes of content |
| 117 static const size_t kMaxBytesToSniff = 512; | 105 static const size_t kMaxBytesToSniff = 512; |
| 118 | 106 |
| 119 // The number of content bytes we need to use all our magic numbers. Feel free | 107 // The number of content bytes we need to use all our magic numbers. Feel free |
| 120 // to increase this number if you add a longer magic number. | 108 // to increase this number if you add a longer magic number. |
| 121 static const size_t kBytesRequiredForMagic = 42; | 109 static const size_t kBytesRequiredForMagic = 42; |
| 122 | 110 |
| 123 struct MagicNumber { | 111 struct MagicNumber { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 MAGIC_HTML_TAG("table") // Mozilla | 199 MAGIC_HTML_TAG("table") // Mozilla |
| 212 MAGIC_HTML_TAG("a") // Mozilla | 200 MAGIC_HTML_TAG("a") // Mozilla |
| 213 MAGIC_HTML_TAG("style") // Mozilla | 201 MAGIC_HTML_TAG("style") // Mozilla |
| 214 MAGIC_HTML_TAG("title") // Mozilla | 202 MAGIC_HTML_TAG("title") // Mozilla |
| 215 MAGIC_HTML_TAG("b") // Mozilla | 203 MAGIC_HTML_TAG("b") // Mozilla |
| 216 MAGIC_HTML_TAG("body") // Mozilla | 204 MAGIC_HTML_TAG("body") // Mozilla |
| 217 MAGIC_HTML_TAG("br") | 205 MAGIC_HTML_TAG("br") |
| 218 MAGIC_HTML_TAG("p") // Mozilla | 206 MAGIC_HTML_TAG("p") // Mozilla |
| 219 }; | 207 }; |
| 220 | 208 |
| 209 static scoped_refptr<Histogram> UMASnifferHistogramGet(const char* name, |
| 210 int array_size) { |
| 211 scoped_refptr<Histogram> counter = |
| 212 LinearHistogram::LinearHistogramFactoryGet( |
| 213 name, 1, array_size - 1, array_size); |
| 214 counter->SetFlags(kUmaTargetedHistogramFlag); |
| 215 return counter; |
| 216 } |
| 217 |
| 221 static bool MatchMagicNumber(const char* content, size_t size, | 218 static bool MatchMagicNumber(const char* content, size_t size, |
| 222 const MagicNumber* magic_entry, | 219 const MagicNumber* magic_entry, |
| 223 std::string* result) { | 220 std::string* result) { |
| 224 const size_t len = magic_entry->magic_len; | 221 const size_t len = magic_entry->magic_len; |
| 225 | 222 |
| 226 // Keep kBytesRequiredForMagic honest. | 223 // Keep kBytesRequiredForMagic honest. |
| 227 DCHECK(len <= kBytesRequiredForMagic); | 224 DCHECK(len <= kBytesRequiredForMagic); |
| 228 | 225 |
| 229 // To compare with magic strings, we need to compute strlen(content), but | 226 // To compare with magic strings, we need to compute strlen(content), but |
| 230 // content might not actually have a null terminator. In that case, we | 227 // content might not actually have a null terminator. In that case, we |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 static bool SniffForHTML(const char* content, size_t size, | 263 static bool SniffForHTML(const char* content, size_t size, |
| 267 std::string* result) { | 264 std::string* result) { |
| 268 // We adopt a strategy similar to that used by Mozilla to sniff HTML tags, | 265 // We adopt a strategy similar to that used by Mozilla to sniff HTML tags, |
| 269 // but with some modifications to better match the HTML5 spec. | 266 // but with some modifications to better match the HTML5 spec. |
| 270 const char* const end = content + size; | 267 const char* const end = content + size; |
| 271 const char* pos; | 268 const char* pos; |
| 272 for (pos = content; pos < end; ++pos) { | 269 for (pos = content; pos < end; ++pos) { |
| 273 if (!IsAsciiWhitespace(*pos)) | 270 if (!IsAsciiWhitespace(*pos)) |
| 274 break; | 271 break; |
| 275 } | 272 } |
| 276 static SnifferHistogram counter("mime_sniffer.kSniffableTags2", | 273 static scoped_refptr<Histogram> counter = |
| 277 arraysize(kSniffableTags)); | 274 UMASnifferHistogramGet("mime_sniffer.kSniffableTags2", |
| 275 arraysize(kSniffableTags)); |
| 278 // |pos| now points to first non-whitespace character (or at end). | 276 // |pos| now points to first non-whitespace character (or at end). |
| 279 return CheckForMagicNumbers(pos, end - pos, | 277 return CheckForMagicNumbers(pos, end - pos, |
| 280 kSniffableTags, arraysize(kSniffableTags), | 278 kSniffableTags, arraysize(kSniffableTags), |
| 281 &counter, result); | 279 counter.get(), result); |
| 282 } | 280 } |
| 283 | 281 |
| 284 static bool SniffForMagicNumbers(const char* content, size_t size, | 282 static bool SniffForMagicNumbers(const char* content, size_t size, |
| 285 std::string* result) { | 283 std::string* result) { |
| 286 // Check our big table of Magic Numbers | 284 // Check our big table of Magic Numbers |
| 287 static SnifferHistogram counter("mime_sniffer.kMagicNumbers2", | 285 static scoped_refptr<Histogram> counter = |
| 288 arraysize(kMagicNumbers)); | 286 UMASnifferHistogramGet("mime_sniffer.kMagicNumbers2", |
| 287 arraysize(kMagicNumbers)); |
| 289 return CheckForMagicNumbers(content, size, | 288 return CheckForMagicNumbers(content, size, |
| 290 kMagicNumbers, arraysize(kMagicNumbers), | 289 kMagicNumbers, arraysize(kMagicNumbers), |
| 291 &counter, result); | 290 counter.get(), result); |
| 292 } | 291 } |
| 293 | 292 |
| 294 // Byte order marks | 293 // Byte order marks |
| 295 static const MagicNumber kMagicXML[] = { | 294 static const MagicNumber kMagicXML[] = { |
| 296 // We want to be very conservative in interpreting text/xml content as | 295 // We want to be very conservative in interpreting text/xml content as |
| 297 // XHTML -- we just want to sniff enough to make unit tests pass. | 296 // XHTML -- we just want to sniff enough to make unit tests pass. |
| 298 // So we match explicitly on this, and don't match other ways of writing | 297 // So we match explicitly on this, and don't match other ways of writing |
| 299 // it in semantically-equivalent ways. | 298 // it in semantically-equivalent ways. |
| 300 MAGIC_STRING("application/xhtml+xml", | 299 MAGIC_STRING("application/xhtml+xml", |
| 301 "<html xmlns=\"http://www.w3.org/1999/xhtml\"") | 300 "<html xmlns=\"http://www.w3.org/1999/xhtml\"") |
| (...skipping 11 matching lines...) Expand all Loading... |
| 313 // We allow at most kFirstTagBytes bytes of content before we expect the | 312 // We allow at most kFirstTagBytes bytes of content before we expect the |
| 314 // opening tag. | 313 // opening tag. |
| 315 const size_t kFeedAllowedHeaderBytes = 300; | 314 const size_t kFeedAllowedHeaderBytes = 300; |
| 316 const char* const end = content + std::min(size, kFeedAllowedHeaderBytes); | 315 const char* const end = content + std::min(size, kFeedAllowedHeaderBytes); |
| 317 const char* pos = content; | 316 const char* pos = content; |
| 318 | 317 |
| 319 // This loop iterates through tag-looking offsets in the file. | 318 // This loop iterates through tag-looking offsets in the file. |
| 320 // We want to skip XML processing instructions (of the form "<?xml ...") | 319 // We want to skip XML processing instructions (of the form "<?xml ...") |
| 321 // and stop at the first "plain" tag, then make a decision on the mime-type | 320 // and stop at the first "plain" tag, then make a decision on the mime-type |
| 322 // based on the name (or possibly attributes) of that tag. | 321 // based on the name (or possibly attributes) of that tag. |
| 323 static SnifferHistogram counter("mime_sniffer.kMagicXML2", | 322 static scoped_refptr<Histogram> counter = |
| 324 arraysize(kMagicXML)); | 323 UMASnifferHistogramGet("mime_sniffer.kMagicXML2", |
| 324 arraysize(kMagicXML)); |
| 325 const int kMaxTagIterations = 5; | 325 const int kMaxTagIterations = 5; |
| 326 for (int i = 0; i < kMaxTagIterations && pos < end; ++i) { | 326 for (int i = 0; i < kMaxTagIterations && pos < end; ++i) { |
| 327 pos = reinterpret_cast<const char*>(memchr(pos, '<', end - pos)); | 327 pos = reinterpret_cast<const char*>(memchr(pos, '<', end - pos)); |
| 328 if (!pos) | 328 if (!pos) |
| 329 return false; | 329 return false; |
| 330 | 330 |
| 331 if (base::strncasecmp(pos, "<?xml", sizeof("<?xml")-1) == 0) { | 331 if (base::strncasecmp(pos, "<?xml", sizeof("<?xml")-1) == 0) { |
| 332 // Skip XML declarations. | 332 // Skip XML declarations. |
| 333 ++pos; | 333 ++pos; |
| 334 continue; | 334 continue; |
| 335 } else if (base::strncasecmp(pos, "<!DOCTYPE", | 335 } else if (base::strncasecmp(pos, "<!DOCTYPE", |
| 336 sizeof("<!DOCTYPE")-1) == 0) { | 336 sizeof("<!DOCTYPE")-1) == 0) { |
| 337 // Skip DOCTYPE declarations. | 337 // Skip DOCTYPE declarations. |
| 338 ++pos; | 338 ++pos; |
| 339 continue; | 339 continue; |
| 340 } | 340 } |
| 341 | 341 |
| 342 if (CheckForMagicNumbers(pos, end - pos, | 342 if (CheckForMagicNumbers(pos, end - pos, |
| 343 kMagicXML, arraysize(kMagicXML), | 343 kMagicXML, arraysize(kMagicXML), |
| 344 &counter, result)) | 344 counter.get(), result)) |
| 345 return true; | 345 return true; |
| 346 | 346 |
| 347 // TODO(evanm): handle RSS 1.0, which is an RDF format and more difficult | 347 // TODO(evanm): handle RSS 1.0, which is an RDF format and more difficult |
| 348 // to identify. | 348 // to identify. |
| 349 | 349 |
| 350 // If we get here, we've hit an initial tag that hasn't matched one of the | 350 // If we get here, we've hit an initial tag that hasn't matched one of the |
| 351 // above tests. Abort. | 351 // above tests. Abort. |
| 352 return true; | 352 return true; |
| 353 } | 353 } |
| 354 | 354 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0 - 0xAF | 381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0 - 0xAF |
| 382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0 - 0xBF | 382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0 - 0xBF |
| 383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0 - 0xCF | 383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0 - 0xCF |
| 384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0 - 0xDF | 384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0 - 0xDF |
| 385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0 - 0xEF | 385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0 - 0xEF |
| 386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xF0 - 0xFF | 386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xF0 - 0xFF |
| 387 }; | 387 }; |
| 388 | 388 |
| 389 static bool LooksBinary(const char* content, size_t size) { | 389 static bool LooksBinary(const char* content, size_t size) { |
| 390 // First, we look for a BOM. | 390 // First, we look for a BOM. |
| 391 static SnifferHistogram counter("mime_sniffer.kByteOrderMark2", | 391 static scoped_refptr<Histogram> counter = |
| 392 arraysize(kByteOrderMark)); | 392 UMASnifferHistogramGet("mime_sniffer.kByteOrderMark2", |
| 393 arraysize(kByteOrderMark)); |
| 393 std::string unused; | 394 std::string unused; |
| 394 if (CheckForMagicNumbers(content, size, | 395 if (CheckForMagicNumbers(content, size, |
| 395 kByteOrderMark, arraysize(kByteOrderMark), | 396 kByteOrderMark, arraysize(kByteOrderMark), |
| 396 &counter, &unused)) { | 397 counter.get(), &unused)) { |
| 397 // If there is BOM, we think the buffer is not binary. | 398 // If there is BOM, we think the buffer is not binary. |
| 398 return false; | 399 return false; |
| 399 } | 400 } |
| 400 | 401 |
| 401 // Next we look to see if any of the bytes "look binary." | 402 // Next we look to see if any of the bytes "look binary." |
| 402 for (size_t i = 0; i < size; ++i) { | 403 for (size_t i = 0; i < size; ++i) { |
| 403 // If we a see a binary-looking byte, we think the content is binary. | 404 // If we a see a binary-looking byte, we think the content is binary. |
| 404 if (kByteLooksBinary[static_cast<unsigned char>(content[i])]) | 405 if (kByteLooksBinary[static_cast<unsigned char>(content[i])]) |
| 405 return true; | 406 return true; |
| 406 } | 407 } |
| 407 | 408 |
| 408 // No evidence either way, default to non-binary. | 409 // No evidence either way, default to non-binary. |
| 409 return false; | 410 return false; |
| 410 } | 411 } |
| 411 | 412 |
| 412 static bool IsUnknownMimeType(const std::string& mime_type) { | 413 static bool IsUnknownMimeType(const std::string& mime_type) { |
| 413 // TODO(tc): Maybe reuse some code in net/http/http_response_headers.* here. | 414 // TODO(tc): Maybe reuse some code in net/http/http_response_headers.* here. |
| 414 // If we do, please be careful not to alter the semantics at all. | 415 // If we do, please be careful not to alter the semantics at all. |
| 415 static const char* kUnknownMimeTypes[] = { | 416 static const char* kUnknownMimeTypes[] = { |
| 416 // Empty mime types are as unknown as they get. | 417 // Empty mime types are as unknown as they get. |
| 417 "", | 418 "", |
| 418 // The unknown/unknown type is popular and uninformative | 419 // The unknown/unknown type is popular and uninformative |
| 419 "unknown/unknown", | 420 "unknown/unknown", |
| 420 // The second most popular unknown mime type is application/unknown | 421 // The second most popular unknown mime type is application/unknown |
| 421 "application/unknown", | 422 "application/unknown", |
| 422 // Firefox rejects a mime type if it is exactly */* | 423 // Firefox rejects a mime type if it is exactly */* |
| 423 "*/*", | 424 "*/*", |
| 424 }; | 425 }; |
| 425 static SnifferHistogram counter("mime_sniffer.kUnknownMimeTypes2", | 426 static scoped_refptr<Histogram> counter = |
| 426 arraysize(kUnknownMimeTypes) + 1); | 427 UMASnifferHistogramGet("mime_sniffer.kUnknownMimeTypes2", |
| 428 arraysize(kUnknownMimeTypes) + 1); |
| 427 for (size_t i = 0; i < arraysize(kUnknownMimeTypes); ++i) { | 429 for (size_t i = 0; i < arraysize(kUnknownMimeTypes); ++i) { |
| 428 if (mime_type == kUnknownMimeTypes[i]) { | 430 if (mime_type == kUnknownMimeTypes[i]) { |
| 429 counter.Add(i); | 431 counter->Add(i); |
| 430 return true; | 432 return true; |
| 431 } | 433 } |
| 432 } | 434 } |
| 433 if (mime_type.find('/') == std::string::npos) { | 435 if (mime_type.find('/') == std::string::npos) { |
| 434 // Firefox rejects a mime type if it does not contain a slash | 436 // Firefox rejects a mime type if it does not contain a slash |
| 435 counter.Add(arraysize(kUnknownMimeTypes)); | 437 counter->Add(arraysize(kUnknownMimeTypes)); |
| 436 return true; | 438 return true; |
| 437 } | 439 } |
| 438 return false; | 440 return false; |
| 439 } | 441 } |
| 440 | 442 |
| 441 // Sniff a crx (chrome extension) file. | 443 // Sniff a crx (chrome extension) file. |
| 442 static bool SniffCRX(const char* content, size_t content_size, const GURL& url, | 444 static bool SniffCRX(const char* content, size_t content_size, const GURL& url, |
| 443 const std::string& type_hint, std::string* result) { | 445 const std::string& type_hint, std::string* result) { |
| 444 static SnifferHistogram counter("mime_sniffer.kSniffCRX", 3); | 446 static scoped_refptr<Histogram> counter = |
| 447 UMASnifferHistogramGet("mime_sniffer.kSniffCRX", 3); |
| 445 | 448 |
| 446 // Technically, the crx magic number is just Cr24, but the bytes after that | 449 // Technically, the crx magic number is just Cr24, but the bytes after that |
| 447 // are a version number which changes infrequently. Including it in the | 450 // are a version number which changes infrequently. Including it in the |
| 448 // sniffing gives us less room for error. If the version number ever changes, | 451 // sniffing gives us less room for error. If the version number ever changes, |
| 449 // we can just add an entry to this list. | 452 // we can just add an entry to this list. |
| 450 // | 453 // |
| 451 // TODO(aa): If we ever have another magic number, we'll want to pass a | 454 // TODO(aa): If we ever have another magic number, we'll want to pass a |
| 452 // histogram into CheckForMagicNumbers(), below, to see which one matched. | 455 // histogram into CheckForMagicNumbers(), below, to see which one matched. |
| 453 const struct MagicNumber kCRXMagicNumbers[] = { | 456 const struct MagicNumber kCRXMagicNumbers[] = { |
| 454 MAGIC_NUMBER("application/x-chrome-extension", "Cr24\x02\x00\x00\x00") | 457 MAGIC_NUMBER("application/x-chrome-extension", "Cr24\x02\x00\x00\x00") |
| 455 }; | 458 }; |
| 456 | 459 |
| 457 // Only consider files that have the extension ".crx". | 460 // Only consider files that have the extension ".crx". |
| 458 const char kCRXExtension[] = ".crx"; | 461 const char kCRXExtension[] = ".crx"; |
| 459 const int kExtensionLength = arraysize(kCRXExtension) - 1; // ignore null | 462 const int kExtensionLength = arraysize(kCRXExtension) - 1; // ignore null |
| 460 if (url.path().rfind(kCRXExtension, std::string::npos, kExtensionLength) == | 463 if (url.path().rfind(kCRXExtension, std::string::npos, kExtensionLength) == |
| 461 url.path().size() - kExtensionLength) { | 464 url.path().size() - kExtensionLength) { |
| 462 counter.Add(1); | 465 counter->Add(1); |
| 463 } else { | 466 } else { |
| 464 return false; | 467 return false; |
| 465 } | 468 } |
| 466 | 469 |
| 467 if (CheckForMagicNumbers(content, content_size, | 470 if (CheckForMagicNumbers(content, content_size, |
| 468 kCRXMagicNumbers, arraysize(kCRXMagicNumbers), | 471 kCRXMagicNumbers, arraysize(kCRXMagicNumbers), |
| 469 NULL, result)) { | 472 NULL, result)) { |
| 470 counter.Add(2); | 473 counter->Add(2); |
| 471 } else { | 474 } else { |
| 472 return false; | 475 return false; |
| 473 } | 476 } |
| 474 | 477 |
| 475 return true; | 478 return true; |
| 476 } | 479 } |
| 477 | 480 |
| 478 bool ShouldSniffMimeType(const GURL& url, const std::string& mime_type) { | 481 bool ShouldSniffMimeType(const GURL& url, const std::string& mime_type) { |
| 479 static SnifferHistogram should_sniff_counter( | 482 static scoped_refptr<Histogram> should_sniff_counter = |
| 480 "mime_sniffer.ShouldSniffMimeType2", 3); | 483 UMASnifferHistogramGet("mime_sniffer.ShouldSniffMimeType2", 3); |
| 481 // We are willing to sniff the mime type for HTTP, HTTPS, and FTP | 484 // We are willing to sniff the mime type for HTTP, HTTPS, and FTP |
| 482 bool sniffable_scheme = url.is_empty() || | 485 bool sniffable_scheme = url.is_empty() || |
| 483 url.SchemeIs("http") || | 486 url.SchemeIs("http") || |
| 484 url.SchemeIs("https") || | 487 url.SchemeIs("https") || |
| 485 url.SchemeIs("ftp"); | 488 url.SchemeIs("ftp"); |
| 486 if (!sniffable_scheme) { | 489 if (!sniffable_scheme) { |
| 487 should_sniff_counter.Add(1); | 490 should_sniff_counter->Add(1); |
| 488 return false; | 491 return false; |
| 489 } | 492 } |
| 490 | 493 |
| 491 static const char* kSniffableTypes[] = { | 494 static const char* kSniffableTypes[] = { |
| 492 // Many web servers are misconfigured to send text/plain for many | 495 // Many web servers are misconfigured to send text/plain for many |
| 493 // different types of content. | 496 // different types of content. |
| 494 "text/plain", | 497 "text/plain", |
| 495 // IIS 4.0 and 5.0 send application/octet-stream when serving .xhtml | 498 // IIS 4.0 and 5.0 send application/octet-stream when serving .xhtml |
| 496 // files. Firefox 2.0 does not sniff xhtml here, but Safari 3, | 499 // files. Firefox 2.0 does not sniff xhtml here, but Safari 3, |
| 497 // Opera 9, and IE do. | 500 // Opera 9, and IE do. |
| 498 "application/octet-stream", | 501 "application/octet-stream", |
| 499 // XHTML and Atom/RSS feeds are often served as plain xml instead of | 502 // XHTML and Atom/RSS feeds are often served as plain xml instead of |
| 500 // their more specific mime types. | 503 // their more specific mime types. |
| 501 "text/xml", | 504 "text/xml", |
| 502 "application/xml", | 505 "application/xml", |
| 503 }; | 506 }; |
| 504 static SnifferHistogram counter("mime_sniffer.kSniffableTypes2", | 507 static scoped_refptr<Histogram> counter = |
| 505 arraysize(kSniffableTypes) + 1); | 508 UMASnifferHistogramGet("mime_sniffer.kSniffableTypes2", |
| 509 arraysize(kSniffableTypes) + 1); |
| 506 for (size_t i = 0; i < arraysize(kSniffableTypes); ++i) { | 510 for (size_t i = 0; i < arraysize(kSniffableTypes); ++i) { |
| 507 if (mime_type == kSniffableTypes[i]) { | 511 if (mime_type == kSniffableTypes[i]) { |
| 508 counter.Add(i); | 512 counter->Add(i); |
| 509 should_sniff_counter.Add(2); | 513 should_sniff_counter->Add(2); |
| 510 return true; | 514 return true; |
| 511 } | 515 } |
| 512 } | 516 } |
| 513 if (IsUnknownMimeType(mime_type)) { | 517 if (IsUnknownMimeType(mime_type)) { |
| 514 // The web server didn't specify a content type or specified a mime | 518 // The web server didn't specify a content type or specified a mime |
| 515 // type that we ignore. | 519 // type that we ignore. |
| 516 counter.Add(arraysize(kSniffableTypes)); | 520 counter->Add(arraysize(kSniffableTypes)); |
| 517 should_sniff_counter.Add(2); | 521 should_sniff_counter->Add(2); |
| 518 return true; | 522 return true; |
| 519 } | 523 } |
| 520 should_sniff_counter.Add(1); | 524 should_sniff_counter->Add(1); |
| 521 return false; | 525 return false; |
| 522 } | 526 } |
| 523 | 527 |
| 524 bool SniffMimeType(const char* content, size_t content_size, | 528 bool SniffMimeType(const char* content, size_t content_size, |
| 525 const GURL& url, const std::string& type_hint, | 529 const GURL& url, const std::string& type_hint, |
| 526 std::string* result) { | 530 std::string* result) { |
| 527 DCHECK_LT(content_size, 1000000U); // sanity check | 531 DCHECK_LT(content_size, 1000000U); // sanity check |
| 528 DCHECK(content); | 532 DCHECK(content); |
| 529 DCHECK(result); | 533 DCHECK(result); |
| 530 | 534 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 result->assign("text/plain"); | 595 result->assign("text/plain"); |
| 592 // We could change our mind if a binary-looking byte appears later in | 596 // We could change our mind if a binary-looking byte appears later in |
| 593 // the content, so we only have enough content if we have the max. | 597 // the content, so we only have enough content if we have the max. |
| 594 return content_size >= kMaxBytesToSniff; | 598 return content_size >= kMaxBytesToSniff; |
| 595 } | 599 } |
| 596 | 600 |
| 597 return have_enough_content; | 601 return have_enough_content; |
| 598 } | 602 } |
| 599 | 603 |
| 600 } // namespace net | 604 } // namespace net |
| OLD | NEW |