| 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 <algorithm> | 5 #include <algorithm> |
| 6 #include <iterator> | 6 #include <iterator> |
| 7 #include <map> | 7 #include <map> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/containers/hash_tables.h" | 10 #include "base/containers/hash_tables.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 using std::string; | 26 using std::string; |
| 27 | 27 |
| 28 namespace { | 28 namespace { |
| 29 | 29 |
| 30 struct MediaType { | 30 struct MediaType { |
| 31 const char name[12]; | 31 const char name[12]; |
| 32 const char matcher[13]; | 32 const char matcher[13]; |
| 33 }; | 33 }; |
| 34 | 34 |
| 35 static const MediaType kIanaMediaTypes[] = { | 35 static const MediaType kIanaMediaTypes[] = { |
| 36 { "application", "application/" }, | 36 {"application", "application/"}, |
| 37 { "audio", "audio/" }, | 37 {"audio", "audio/"}, |
| 38 { "example", "example/" }, | 38 {"example", "example/"}, |
| 39 { "image", "image/" }, | 39 {"image", "image/"}, |
| 40 { "message", "message/" }, | 40 {"message", "message/"}, |
| 41 { "model", "model/" }, | 41 {"model", "model/"}, |
| 42 { "multipart", "multipart/" }, | 42 {"multipart", "multipart/"}, |
| 43 { "text", "text/" }, | 43 {"text", "text/"}, |
| 44 { "video", "video/" }, | 44 {"video", "video/"}, |
| 45 }; | 45 }; |
| 46 | 46 |
| 47 } // namespace | 47 } // namespace |
| 48 | 48 |
| 49 namespace net { | 49 namespace net { |
| 50 | 50 |
| 51 // Singleton utility class for mime types. | 51 // Singleton utility class for mime types. |
| 52 class MimeUtil : public PlatformMimeUtil { | 52 class MimeUtil : public PlatformMimeUtil { |
| 53 public: | 53 public: |
| 54 enum Codec { | 54 enum Codec { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 80 std::string* mime_type) const; | 80 std::string* mime_type) const; |
| 81 | 81 |
| 82 bool IsSupportedImageMimeType(const std::string& mime_type) const; | 82 bool IsSupportedImageMimeType(const std::string& mime_type) const; |
| 83 bool IsSupportedMediaMimeType(const std::string& mime_type) const; | 83 bool IsSupportedMediaMimeType(const std::string& mime_type) const; |
| 84 bool IsSupportedNonImageMimeType(const std::string& mime_type) const; | 84 bool IsSupportedNonImageMimeType(const std::string& mime_type) const; |
| 85 bool IsUnsupportedTextMimeType(const std::string& mime_type) const; | 85 bool IsUnsupportedTextMimeType(const std::string& mime_type) const; |
| 86 bool IsSupportedJavascriptMimeType(const std::string& mime_type) const; | 86 bool IsSupportedJavascriptMimeType(const std::string& mime_type) const; |
| 87 | 87 |
| 88 bool IsSupportedMimeType(const std::string& mime_type) const; | 88 bool IsSupportedMimeType(const std::string& mime_type) const; |
| 89 | 89 |
| 90 bool MatchesMimeType(const std::string &mime_type_pattern, | 90 bool MatchesMimeType(const std::string& mime_type_pattern, |
| 91 const std::string &mime_type) const; | 91 const std::string& mime_type) const; |
| 92 | 92 |
| 93 bool ParseMimeTypeWithoutParameter(const std::string& type_string, | 93 bool ParseMimeTypeWithoutParameter(const std::string& type_string, |
| 94 std::string* top_level_type, | 94 std::string* top_level_type, |
| 95 std::string* subtype) const; | 95 std::string* subtype) const; |
| 96 | 96 |
| 97 bool IsValidTopLevelMimeType(const std::string& type_string) const; | 97 bool IsValidTopLevelMimeType(const std::string& type_string) const; |
| 98 | 98 |
| 99 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const; | 99 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const; |
| 100 | 100 |
| 101 void ParseCodecString(const std::string& codecs, | 101 void ParseCodecString(const std::string& codecs, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 124 }; | 124 }; |
| 125 typedef std::map<std::string, CodecEntry> StringToCodecMappings; | 125 typedef std::map<std::string, CodecEntry> StringToCodecMappings; |
| 126 | 126 |
| 127 MimeUtil(); | 127 MimeUtil(); |
| 128 | 128 |
| 129 // Returns IsSupported if all codec IDs in |codecs| are unambiguous | 129 // Returns IsSupported if all codec IDs in |codecs| are unambiguous |
| 130 // and are supported by the platform. MayBeSupported is returned if | 130 // and are supported by the platform. MayBeSupported is returned if |
| 131 // at least one codec ID in |codecs| is ambiguous but all the codecs | 131 // at least one codec ID in |codecs| is ambiguous but all the codecs |
| 132 // are supported by the platform. IsNotSupported is returned if at | 132 // are supported by the platform. IsNotSupported is returned if at |
| 133 // least one codec ID is not supported by the platform. | 133 // least one codec ID is not supported by the platform. |
| 134 SupportsType AreSupportedCodecs( | 134 SupportsType AreSupportedCodecs(const CodecSet& supported_codecs, |
| 135 const CodecSet& supported_codecs, | 135 const std::vector<std::string>& codecs) const; |
| 136 const std::vector<std::string>& codecs) const; | |
| 137 | 136 |
| 138 // For faster lookup, keep hash sets. | 137 // For faster lookup, keep hash sets. |
| 139 void InitializeMimeTypeMaps(); | 138 void InitializeMimeTypeMaps(); |
| 140 | 139 |
| 141 bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext, | 140 bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext, |
| 142 bool include_platform_types, | 141 bool include_platform_types, |
| 143 std::string* mime_type) const; | 142 std::string* mime_type) const; |
| 144 | 143 |
| 145 // Converts a codec ID into an Codec enum value and indicates | 144 // Converts a codec ID into an Codec enum value and indicates |
| 146 // whether the conversion was ambiguous. | 145 // whether the conversion was ambiguous. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 // This variable is Leaky because we need to access it from WorkerPool threads. | 191 // This variable is Leaky because we need to access it from WorkerPool threads. |
| 193 static base::LazyInstance<MimeUtil>::Leaky g_mime_util = | 192 static base::LazyInstance<MimeUtil>::Leaky g_mime_util = |
| 194 LAZY_INSTANCE_INITIALIZER; | 193 LAZY_INSTANCE_INITIALIZER; |
| 195 | 194 |
| 196 struct MimeInfo { | 195 struct MimeInfo { |
| 197 const char* mime_type; | 196 const char* mime_type; |
| 198 const char* extensions; // comma separated list | 197 const char* extensions; // comma separated list |
| 199 }; | 198 }; |
| 200 | 199 |
| 201 static const MimeInfo primary_mappings[] = { | 200 static const MimeInfo primary_mappings[] = { |
| 202 { "text/html", "html,htm,shtml,shtm" }, | 201 {"text/html", "html,htm,shtml,shtm"}, |
| 203 { "text/css", "css" }, | 202 {"text/css", "css"}, |
| 204 { "text/xml", "xml" }, | 203 {"text/xml", "xml"}, |
| 205 { "image/gif", "gif" }, | 204 {"image/gif", "gif"}, |
| 206 { "image/jpeg", "jpeg,jpg" }, | 205 {"image/jpeg", "jpeg,jpg"}, |
| 207 { "image/webp", "webp" }, | 206 {"image/webp", "webp"}, |
| 208 { "image/png", "png" }, | 207 {"image/png", "png"}, |
| 209 { "video/mp4", "mp4,m4v" }, | 208 {"video/mp4", "mp4,m4v"}, |
| 210 { "audio/x-m4a", "m4a" }, | 209 {"audio/x-m4a", "m4a"}, |
| 211 { "audio/mp3", "mp3" }, | 210 {"audio/mp3", "mp3"}, |
| 212 { "video/ogg", "ogv,ogm" }, | 211 {"video/ogg", "ogv,ogm"}, |
| 213 { "audio/ogg", "ogg,oga,opus" }, | 212 {"audio/ogg", "ogg,oga,opus"}, |
| 214 { "video/webm", "webm" }, | 213 {"video/webm", "webm"}, |
| 215 { "audio/webm", "webm" }, | 214 {"audio/webm", "webm"}, |
| 216 { "audio/wav", "wav" }, | 215 {"audio/wav", "wav"}, |
| 217 { "application/xhtml+xml", "xhtml,xht,xhtm" }, | 216 {"application/xhtml+xml", "xhtml,xht,xhtm"}, |
| 218 { "application/x-chrome-extension", "crx" }, | 217 {"application/x-chrome-extension", "crx"}, |
| 219 { "multipart/related", "mhtml,mht" } | 218 {"multipart/related", "mhtml,mht"}}; |
| 220 }; | |
| 221 | 219 |
| 222 static const MimeInfo secondary_mappings[] = { | 220 static const MimeInfo secondary_mappings[] = { |
| 223 { "application/octet-stream", "exe,com,bin" }, | 221 {"application/octet-stream", "exe,com,bin"}, |
| 224 { "application/gzip", "gz" }, | 222 {"application/gzip", "gz"}, |
| 225 { "application/pdf", "pdf" }, | 223 {"application/pdf", "pdf"}, |
| 226 { "application/postscript", "ps,eps,ai" }, | 224 {"application/postscript", "ps,eps,ai"}, |
| 227 { "application/javascript", "js" }, | 225 {"application/javascript", "js"}, |
| 228 { "application/font-woff", "woff" }, | 226 {"application/font-woff", "woff"}, |
| 229 { "image/bmp", "bmp" }, | 227 {"image/bmp", "bmp"}, |
| 230 { "image/x-icon", "ico" }, | 228 {"image/x-icon", "ico"}, |
| 231 { "image/vnd.microsoft.icon", "ico" }, | 229 {"image/vnd.microsoft.icon", "ico"}, |
| 232 { "image/jpeg", "jfif,pjpeg,pjp" }, | 230 {"image/jpeg", "jfif,pjpeg,pjp"}, |
| 233 { "image/tiff", "tiff,tif" }, | 231 {"image/tiff", "tiff,tif"}, |
| 234 { "image/x-xbitmap", "xbm" }, | 232 {"image/x-xbitmap", "xbm"}, |
| 235 { "image/svg+xml", "svg,svgz" }, | 233 {"image/svg+xml", "svg,svgz"}, |
| 236 { "image/x-png", "png"}, | 234 {"image/x-png", "png"}, |
| 237 { "message/rfc822", "eml" }, | 235 {"message/rfc822", "eml"}, |
| 238 { "text/plain", "txt,text" }, | 236 {"text/plain", "txt,text"}, |
| 239 { "text/html", "ehtml" }, | 237 {"text/html", "ehtml"}, |
| 240 { "application/rss+xml", "rss" }, | 238 {"application/rss+xml", "rss"}, |
| 241 { "application/rdf+xml", "rdf" }, | 239 {"application/rdf+xml", "rdf"}, |
| 242 { "text/xml", "xsl,xbl,xslt" }, | 240 {"text/xml", "xsl,xbl,xslt"}, |
| 243 { "application/vnd.mozilla.xul+xml", "xul" }, | 241 {"application/vnd.mozilla.xul+xml", "xul"}, |
| 244 { "application/x-shockwave-flash", "swf,swl" }, | 242 {"application/x-shockwave-flash", "swf,swl"}, |
| 245 { "application/pkcs7-mime", "p7m,p7c,p7z" }, | 243 {"application/pkcs7-mime", "p7m,p7c,p7z"}, |
| 246 { "application/pkcs7-signature", "p7s" }, | 244 {"application/pkcs7-signature", "p7s"}, |
| 247 { "application/x-mpegurl", "m3u8" }, | 245 {"application/x-mpegurl", "m3u8"}, |
| 248 }; | 246 }; |
| 249 | 247 |
| 250 static const char* FindMimeType(const MimeInfo* mappings, | 248 static const char* FindMimeType(const MimeInfo* mappings, |
| 251 size_t mappings_len, | 249 size_t mappings_len, |
| 252 const char* ext) { | 250 const char* ext) { |
| 253 size_t ext_len = strlen(ext); | 251 size_t ext_len = strlen(ext); |
| 254 | 252 |
| 255 for (size_t i = 0; i < mappings_len; ++i) { | 253 for (size_t i = 0; i < mappings_len; ++i) { |
| 256 const char* extensions = mappings[i].extensions; | 254 const char* extensions = mappings[i].extensions; |
| 257 for (;;) { | 255 for (;;) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 return false; | 295 return false; |
| 298 | 296 |
| 299 // We implement the same algorithm as Mozilla for mapping a file extension to | 297 // We implement the same algorithm as Mozilla for mapping a file extension to |
| 300 // a mime type. That is, we first check a hard-coded list (that cannot be | 298 // a mime type. That is, we first check a hard-coded list (that cannot be |
| 301 // overridden), and then if not found there, we defer to the system registry. | 299 // overridden), and then if not found there, we defer to the system registry. |
| 302 // Finally, we scan a secondary hard-coded list to catch types that we can | 300 // Finally, we scan a secondary hard-coded list to catch types that we can |
| 303 // deduce but that we also want to allow the OS to override. | 301 // deduce but that we also want to allow the OS to override. |
| 304 | 302 |
| 305 base::FilePath path_ext(ext); | 303 base::FilePath path_ext(ext); |
| 306 const string ext_narrow_str = path_ext.AsUTF8Unsafe(); | 304 const string ext_narrow_str = path_ext.AsUTF8Unsafe(); |
| 307 const char* mime_type = FindMimeType(primary_mappings, | 305 const char* mime_type = FindMimeType( |
| 308 arraysize(primary_mappings), | 306 primary_mappings, arraysize(primary_mappings), ext_narrow_str.c_str()); |
| 309 ext_narrow_str.c_str()); | |
| 310 if (mime_type) { | 307 if (mime_type) { |
| 311 *result = mime_type; | 308 *result = mime_type; |
| 312 return true; | 309 return true; |
| 313 } | 310 } |
| 314 | 311 |
| 315 if (include_platform_types && GetPlatformMimeTypeFromExtension(ext, result)) | 312 if (include_platform_types && GetPlatformMimeTypeFromExtension(ext, result)) |
| 316 return true; | 313 return true; |
| 317 | 314 |
| 318 mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings), | 315 mime_type = FindMimeType(secondary_mappings, |
| 316 arraysize(secondary_mappings), |
| 319 ext_narrow_str.c_str()); | 317 ext_narrow_str.c_str()); |
| 320 if (mime_type) { | 318 if (mime_type) { |
| 321 *result = mime_type; | 319 *result = mime_type; |
| 322 return true; | 320 return true; |
| 323 } | 321 } |
| 324 | 322 |
| 325 return false; | 323 return false; |
| 326 } | 324 } |
| 327 | 325 |
| 328 // From WebKit's WebCore/platform/MIMETypeRegistry.cpp: | 326 // From WebKit's WebCore/platform/MIMETypeRegistry.cpp: |
| 329 | 327 |
| 330 static const char* const supported_image_types[] = { | 328 static const char* const supported_image_types[] = { |
| 331 "image/jpeg", | 329 "image/jpeg", |
| 332 "image/pjpeg", | 330 "image/pjpeg", |
| 333 "image/jpg", | 331 "image/jpg", |
| 334 "image/webp", | 332 "image/webp", |
| 335 "image/png", | 333 "image/png", |
| 336 "image/gif", | 334 "image/gif", |
| 337 "image/bmp", | 335 "image/bmp", |
| 338 "image/vnd.microsoft.icon", // ico | 336 "image/vnd.microsoft.icon", // ico |
| 339 "image/x-icon", // ico | 337 "image/x-icon", // ico |
| 340 "image/x-xbitmap", // xbm | 338 "image/x-xbitmap", // xbm |
| 341 "image/x-png" | 339 "image/x-png"}; |
| 342 }; | |
| 343 | 340 |
| 344 // A list of media types: http://en.wikipedia.org/wiki/Internet_media_type | 341 // A list of media types: http://en.wikipedia.org/wiki/Internet_media_type |
| 345 // A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php | 342 // A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php |
| 346 // This set of codecs is supported by all variations of Chromium. | 343 // This set of codecs is supported by all variations of Chromium. |
| 347 static const char* const common_media_types[] = { | 344 static const char* const common_media_types[] = { |
| 348 // Ogg. | 345 // Ogg. |
| 349 "audio/ogg", | 346 "audio/ogg", |
| 350 "application/ogg", | 347 "application/ogg", |
| 351 #if !defined(OS_ANDROID) // Android doesn't support Ogg Theora. | 348 #if !defined(OS_ANDROID) // Android doesn't support Ogg Theora. |
| 352 "video/ogg", | 349 "video/ogg", |
| 353 #endif | 350 #endif |
| 354 | 351 |
| 355 // WebM. | 352 // WebM. |
| 356 "video/webm", | 353 "video/webm", |
| 357 "audio/webm", | 354 "audio/webm", |
| 358 | 355 |
| 359 // Wav. | 356 // Wav. |
| 360 "audio/wav", | 357 "audio/wav", |
| 361 "audio/x-wav", | 358 "audio/x-wav", |
| 362 | 359 |
| 363 #if defined(OS_ANDROID) | 360 #if defined(OS_ANDROID) |
| 364 // HLS. Supported by Android ICS and above. | 361 // HLS. Supported by Android ICS and above. |
| 365 "application/vnd.apple.mpegurl", | 362 "application/vnd.apple.mpegurl", |
| 366 "application/x-mpegurl", | 363 "application/x-mpegurl", |
| 367 #endif | 364 #endif |
| 368 }; | 365 }; |
| 369 | 366 |
| 370 // List of proprietary types only supported by Google Chrome. | 367 // List of proprietary types only supported by Google Chrome. |
| 371 static const char* const proprietary_media_types[] = { | 368 static const char* const proprietary_media_types[] = { |
| 372 // MPEG-4. | 369 // MPEG-4. |
| 373 "video/mp4", | 370 "video/mp4", |
| 374 "video/x-m4v", | 371 "video/x-m4v", |
| 375 "audio/mp4", | 372 "audio/mp4", |
| 376 "audio/x-m4a", | 373 "audio/x-m4a", |
| 377 | 374 |
| 378 // MP3. | 375 // MP3. |
| 379 "audio/mp3", | 376 "audio/mp3", |
| 380 "audio/x-mp3", | 377 "audio/x-mp3", |
| 381 "audio/mpeg", | 378 "audio/mpeg", |
| 382 | 379 |
| 383 #if defined(ENABLE_MPEG2TS_STREAM_PARSER) | 380 #if defined(ENABLE_MPEG2TS_STREAM_PARSER) |
| 384 // MPEG-2 TS. | 381 // MPEG-2 TS. |
| 385 "video/mp2t", | 382 "video/mp2t", |
| 386 #endif | 383 #endif |
| 387 }; | 384 }; |
| 388 | 385 |
| 389 // Note: | 386 // Note: |
| 390 // - does not include javascript types list (see supported_javascript_types) | 387 // - does not include javascript types list (see supported_javascript_types) |
| 391 // - does not include types starting with "text/" (see | 388 // - does not include types starting with "text/" (see |
| 392 // IsSupportedNonImageMimeType()) | 389 // IsSupportedNonImageMimeType()) |
| 393 static const char* const supported_non_image_types[] = { | 390 static const char* const supported_non_image_types[] = { |
| 394 "image/svg+xml", // SVG is text-based XML, even though it has an image/ type | 391 "image/svg+xml", // SVG is text-based XML, even though it has an image/ |
| 395 "application/xml", | 392 // type |
| 396 "application/atom+xml", | 393 "application/xml", |
| 397 "application/rss+xml", | 394 "application/atom+xml", |
| 398 "application/xhtml+xml", | 395 "application/rss+xml", |
| 399 "application/json", | 396 "application/xhtml+xml", |
| 400 "multipart/related", // For MHTML support. | 397 "application/json", |
| 401 "multipart/x-mixed-replace" | 398 "multipart/related", // For MHTML support. |
| 402 // Note: ADDING a new type here will probably render it AS HTML. This can | 399 "multipart/x-mixed-replace" |
| 403 // result in cross site scripting. | 400 // Note: ADDING a new type here will probably render it AS HTML. This can |
| 401 // result in cross site scripting. |
| 404 }; | 402 }; |
| 405 | 403 |
| 406 // Dictionary of cryptographic file mime types. | 404 // Dictionary of cryptographic file mime types. |
| 407 struct CertificateMimeTypeInfo { | 405 struct CertificateMimeTypeInfo { |
| 408 const char* mime_type; | 406 const char* mime_type; |
| 409 CertificateMimeType cert_type; | 407 CertificateMimeType cert_type; |
| 410 }; | 408 }; |
| 411 | 409 |
| 412 static const CertificateMimeTypeInfo supported_certificate_types[] = { | 410 static const CertificateMimeTypeInfo supported_certificate_types[] = { |
| 413 { "application/x-x509-user-cert", | 411 {"application/x-x509-user-cert", CERTIFICATE_MIME_TYPE_X509_USER_CERT}, |
| 414 CERTIFICATE_MIME_TYPE_X509_USER_CERT }, | |
| 415 #if defined(OS_ANDROID) | 412 #if defined(OS_ANDROID) |
| 416 { "application/x-x509-ca-cert", CERTIFICATE_MIME_TYPE_X509_CA_CERT }, | 413 {"application/x-x509-ca-cert", CERTIFICATE_MIME_TYPE_X509_CA_CERT}, |
| 417 { "application/x-pkcs12", CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE }, | 414 {"application/x-pkcs12", CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE}, |
| 418 #endif | 415 #endif |
| 419 }; | 416 }; |
| 420 | 417 |
| 421 // These types are excluded from the logic that allows all text/ types because | 418 // These types are excluded from the logic that allows all text/ types because |
| 422 // while they are technically text, it's very unlikely that a user expects to | 419 // while they are technically text, it's very unlikely that a user expects to |
| 423 // see them rendered in text form. | 420 // see them rendered in text form. |
| 424 static const char* const unsupported_text_types[] = { | 421 static const char* const unsupported_text_types[] = { |
| 425 "text/calendar", | 422 "text/calendar", |
| 426 "text/x-calendar", | 423 "text/x-calendar", |
| 427 "text/x-vcalendar", | 424 "text/x-vcalendar", |
| 428 "text/vcalendar", | 425 "text/vcalendar", |
| 429 "text/vcard", | 426 "text/vcard", |
| 430 "text/x-vcard", | 427 "text/x-vcard", |
| 431 "text/directory", | 428 "text/directory", |
| 432 "text/ldif", | 429 "text/ldif", |
| 433 "text/qif", | 430 "text/qif", |
| 434 "text/x-qif", | 431 "text/x-qif", |
| 435 "text/x-csv", | 432 "text/x-csv", |
| 436 "text/x-vcf", | 433 "text/x-vcf", |
| 437 "text/rtf", | 434 "text/rtf", |
| 438 "text/comma-separated-values", | 435 "text/comma-separated-values", |
| 439 "text/csv", | 436 "text/csv", |
| 440 "text/tab-separated-values", | 437 "text/tab-separated-values", |
| 441 "text/tsv", | 438 "text/tsv", |
| 442 "text/ofx", // http://crbug.com/162238 | 439 "text/ofx", // http://crbug.com/162238 |
| 443 "text/vnd.sun.j2me.app-descriptor" // http://crbug.com/176450 | 440 "text/vnd.sun.j2me.app-descriptor" // http://crbug.com/176450 |
| 444 }; | 441 }; |
| 445 | 442 |
| 446 // Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript. | 443 // Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript. |
| 447 // Mozilla 1.8 accepts application/javascript, application/ecmascript, and | 444 // Mozilla 1.8 accepts application/javascript, application/ecmascript, and |
| 448 // application/x-javascript, but WinIE 7 doesn't. | 445 // application/x-javascript, but WinIE 7 doesn't. |
| 449 // WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and | 446 // WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and |
| 450 // text/livescript, but Mozilla 1.8 doesn't. | 447 // text/livescript, but Mozilla 1.8 doesn't. |
| 451 // Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't. | 448 // Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't. |
| 452 // Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a | 449 // Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a |
| 453 // whitespace-only string. | 450 // whitespace-only string. |
| 454 // We want to accept all the values that either of these browsers accept, but | 451 // We want to accept all the values that either of these browsers accept, but |
| 455 // not other values. | 452 // not other values. |
| 456 static const char* const supported_javascript_types[] = { | 453 static const char* const supported_javascript_types[] = { |
| 457 "text/javascript", | 454 "text/javascript", |
| 458 "text/ecmascript", | 455 "text/ecmascript", |
| 459 "application/javascript", | 456 "application/javascript", |
| 460 "application/ecmascript", | 457 "application/ecmascript", |
| 461 "application/x-javascript", | 458 "application/x-javascript", |
| 462 "text/javascript1.1", | 459 "text/javascript1.1", |
| 463 "text/javascript1.2", | 460 "text/javascript1.2", |
| 464 "text/javascript1.3", | 461 "text/javascript1.3", |
| 465 "text/jscript", | 462 "text/jscript", |
| 466 "text/livescript" | 463 "text/livescript"}; |
| 467 }; | |
| 468 | 464 |
| 469 #if defined(OS_ANDROID) | 465 #if defined(OS_ANDROID) |
| 470 static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) { | 466 static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) { |
| 471 switch (codec) { | 467 switch (codec) { |
| 472 case MimeUtil::INVALID_CODEC: | 468 case MimeUtil::INVALID_CODEC: |
| 473 return false; | 469 return false; |
| 474 | 470 |
| 475 case MimeUtil::PCM: | 471 case MimeUtil::PCM: |
| 476 case MimeUtil::MP3: | 472 case MimeUtil::MP3: |
| 477 case MimeUtil::MPEG4_AAC_LC: | 473 case MimeUtil::MPEG4_AAC_LC: |
| (...skipping 23 matching lines...) Expand all Loading... |
| 501 case MimeUtil::THEORA: | 497 case MimeUtil::THEORA: |
| 502 return false; | 498 return false; |
| 503 } | 499 } |
| 504 | 500 |
| 505 return false; | 501 return false; |
| 506 } | 502 } |
| 507 | 503 |
| 508 static bool IsMimeTypeSupportedOnAndroid(const std::string& mimeType) { | 504 static bool IsMimeTypeSupportedOnAndroid(const std::string& mimeType) { |
| 509 // HLS codecs are supported in ICS and above (API level 14) | 505 // HLS codecs are supported in ICS and above (API level 14) |
| 510 if ((!mimeType.compare("application/vnd.apple.mpegurl") || | 506 if ((!mimeType.compare("application/vnd.apple.mpegurl") || |
| 511 !mimeType.compare("application/x-mpegurl")) && | 507 !mimeType.compare("application/x-mpegurl")) && |
| 512 base::android::BuildInfo::GetInstance()->sdk_int() < 14) { | 508 base::android::BuildInfo::GetInstance()->sdk_int() < 14) { |
| 513 return false; | 509 return false; |
| 514 } | 510 } |
| 515 return true; | 511 return true; |
| 516 } | 512 } |
| 517 #endif | 513 #endif |
| 518 | 514 |
| 519 struct MediaFormatStrict { | 515 struct MediaFormatStrict { |
| 520 const char* mime_type; | 516 const char* mime_type; |
| 521 const char* codecs_list; | 517 const char* codecs_list; |
| 522 }; | 518 }; |
| 523 | 519 |
| 524 // Following is the list of RFC 6381 compliant codecs: | 520 // Following is the list of RFC 6381 compliant codecs: |
| 525 // mp4a.66 - MPEG-2 AAC MAIN | 521 // mp4a.66 - MPEG-2 AAC MAIN |
| 526 // mp4a.67 - MPEG-2 AAC LC | 522 // mp4a.67 - MPEG-2 AAC LC |
| 527 // mp4a.68 - MPEG-2 AAC SSR | 523 // mp4a.68 - MPEG-2 AAC SSR |
| 528 // mp4a.69 - MPEG-2 extension to MPEG-1 | 524 // mp4a.69 - MPEG-2 extension to MPEG-1 |
| 529 // mp4a.6B - MPEG-1 audio | 525 // mp4a.6B - MPEG-1 audio |
| 530 // mp4a.40.2 - MPEG-4 AAC LC | 526 // mp4a.40.2 - MPEG-4 AAC LC |
| 531 // mp4a.40.5 - MPEG-4 AAC SBRv1 | 527 // mp4a.40.5 - MPEG-4 AAC SBRv1 |
| 532 // | 528 // |
| 533 // avc1.42E0xx - H.264 Baseline | 529 // avc1.42E0xx - H.264 Baseline |
| 534 // avc1.4D40xx - H.264 Main | 530 // avc1.4D40xx - H.264 Main |
| 535 // avc1.6400xx - H.264 High | 531 // avc1.6400xx - H.264 High |
| 536 static const char kMP4AudioCodecsExpression[] = | 532 static const char kMP4AudioCodecsExpression[] = |
| 537 "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.5"; | 533 "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.5"; |
| 538 static const char kMP4VideoCodecsExpression[] = | 534 static const char kMP4VideoCodecsExpression[] = |
| 539 "avc1.42E00A,avc1.4D400A,avc1.64000A," \ | 535 "avc1.42E00A,avc1.4D400A,avc1.64000A," |
| 540 "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.5"; | 536 "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.5"; |
| 541 | 537 |
| 542 static const MediaFormatStrict format_codec_mappings[] = { | 538 static const MediaFormatStrict format_codec_mappings[] = { |
| 543 { "video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0" }, | 539 {"video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0"}, |
| 544 { "audio/webm", "opus,vorbis" }, | 540 {"audio/webm", "opus,vorbis"}, |
| 545 { "audio/wav", "1" }, | 541 {"audio/wav", "1"}, |
| 546 { "audio/x-wav", "1" }, | 542 {"audio/x-wav", "1"}, |
| 547 { "video/ogg", "opus,theora,vorbis" }, | 543 {"video/ogg", "opus,theora,vorbis"}, |
| 548 { "audio/ogg", "opus,vorbis" }, | 544 {"audio/ogg", "opus,vorbis"}, |
| 549 { "application/ogg", "opus,theora,vorbis" }, | 545 {"application/ogg", "opus,theora,vorbis"}, |
| 550 { "audio/mpeg", "mp3" }, | 546 {"audio/mpeg", "mp3"}, |
| 551 { "audio/mp3", "" }, | 547 {"audio/mp3", ""}, |
| 552 { "audio/x-mp3", "" }, | 548 {"audio/x-mp3", ""}, |
| 553 { "audio/mp4", kMP4AudioCodecsExpression }, | 549 {"audio/mp4", kMP4AudioCodecsExpression}, |
| 554 { "audio/x-m4a", kMP4AudioCodecsExpression }, | 550 {"audio/x-m4a", kMP4AudioCodecsExpression}, |
| 555 { "video/mp4", kMP4VideoCodecsExpression }, | 551 {"video/mp4", kMP4VideoCodecsExpression}, |
| 556 { "video/x-m4v", kMP4VideoCodecsExpression }, | 552 {"video/x-m4v", kMP4VideoCodecsExpression}, |
| 557 { "application/x-mpegurl", kMP4VideoCodecsExpression }, | 553 {"application/x-mpegurl", kMP4VideoCodecsExpression}, |
| 558 { "application/vnd.apple.mpegurl", kMP4VideoCodecsExpression } | 554 {"application/vnd.apple.mpegurl", kMP4VideoCodecsExpression}}; |
| 559 }; | |
| 560 | 555 |
| 561 struct CodecIDMappings { | 556 struct CodecIDMappings { |
| 562 const char* const codec_id; | 557 const char* const codec_id; |
| 563 MimeUtil::Codec codec; | 558 MimeUtil::Codec codec; |
| 564 }; | 559 }; |
| 565 | 560 |
| 566 // List of codec IDs that provide enough information to determine the | 561 // List of codec IDs that provide enough information to determine the |
| 567 // codec and profile being requested. | 562 // codec and profile being requested. |
| 568 // | 563 // |
| 569 // The "mp4a" strings come from RFC 6381. | 564 // The "mp4a" strings come from RFC 6381. |
| 570 static const CodecIDMappings kUnambiguousCodecIDs[] = { | 565 static const CodecIDMappings kUnambiguousCodecIDs[] = { |
| 571 { "1", MimeUtil::PCM }, // We only allow this for WAV so it isn't ambiguous. | 566 {"1", MimeUtil::PCM}, // We only allow this for WAV so it isn't ambiguous. |
| 572 { "mp3", MimeUtil::MP3 }, | 567 {"mp3", MimeUtil::MP3}, |
| 573 { "mp4a.66", MimeUtil::MPEG2_AAC_MAIN }, | 568 {"mp4a.66", MimeUtil::MPEG2_AAC_MAIN}, |
| 574 { "mp4a.67", MimeUtil::MPEG2_AAC_LC }, | 569 {"mp4a.67", MimeUtil::MPEG2_AAC_LC}, |
| 575 { "mp4a.68", MimeUtil::MPEG2_AAC_SSR }, | 570 {"mp4a.68", MimeUtil::MPEG2_AAC_SSR}, |
| 576 { "mp4a.69", MimeUtil::MP3 }, | 571 {"mp4a.69", MimeUtil::MP3}, |
| 577 { "mp4a.6B", MimeUtil::MP3 }, | 572 {"mp4a.6B", MimeUtil::MP3}, |
| 578 { "mp4a.40.2", MimeUtil::MPEG4_AAC_LC }, | 573 {"mp4a.40.2", MimeUtil::MPEG4_AAC_LC}, |
| 579 { "mp4a.40.5", MimeUtil::MPEG4_AAC_SBRv1 }, | 574 {"mp4a.40.5", MimeUtil::MPEG4_AAC_SBRv1}, |
| 580 { "vorbis", MimeUtil::VORBIS }, | 575 {"vorbis", MimeUtil::VORBIS}, |
| 581 { "opus", MimeUtil::OPUS }, | 576 {"opus", MimeUtil::OPUS}, |
| 582 { "vp8", MimeUtil::VP8 }, | 577 {"vp8", MimeUtil::VP8}, |
| 583 { "vp8.0", MimeUtil::VP8 }, | 578 {"vp8.0", MimeUtil::VP8}, |
| 584 { "vp9", MimeUtil::VP9 }, | 579 {"vp9", MimeUtil::VP9}, |
| 585 { "vp9.0", MimeUtil::VP9 }, | 580 {"vp9.0", MimeUtil::VP9}, |
| 586 { "theora", MimeUtil::THEORA } | 581 {"theora", MimeUtil::THEORA}}; |
| 587 }; | |
| 588 | 582 |
| 589 // List of codec IDs that are ambiguous and don't provide | 583 // List of codec IDs that are ambiguous and don't provide |
| 590 // enough information to determine the codec and profile. | 584 // enough information to determine the codec and profile. |
| 591 // The codec in these entries indicate the codec and profile | 585 // The codec in these entries indicate the codec and profile |
| 592 // we assume the user is trying to indicate. | 586 // we assume the user is trying to indicate. |
| 593 static const CodecIDMappings kAmbiguousCodecIDs[] = { | 587 static const CodecIDMappings kAmbiguousCodecIDs[] = { |
| 594 { "mp4a.40", MimeUtil::MPEG4_AAC_LC }, | 588 {"mp4a.40", MimeUtil::MPEG4_AAC_LC}, |
| 595 { "avc1", MimeUtil::H264_BASELINE }, | 589 {"avc1", MimeUtil::H264_BASELINE}, |
| 596 { "avc3", MimeUtil::H264_BASELINE }, | 590 {"avc3", MimeUtil::H264_BASELINE}, |
| 597 }; | 591 }; |
| 598 | 592 |
| 599 MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) { | 593 MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) { |
| 600 InitializeMimeTypeMaps(); | 594 InitializeMimeTypeMaps(); |
| 601 } | 595 } |
| 602 | 596 |
| 603 SupportsType MimeUtil::AreSupportedCodecs( | 597 SupportsType MimeUtil::AreSupportedCodecs( |
| 604 const CodecSet& supported_codecs, | 598 const CodecSet& supported_codecs, |
| 605 const std::vector<std::string>& codecs) const { | 599 const std::vector<std::string>& codecs) const { |
| 606 DCHECK(!supported_codecs.empty()); | 600 DCHECK(!supported_codecs.empty()); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 674 } | 668 } |
| 675 | 669 |
| 676 for (size_t i = 0; i < arraysize(kAmbiguousCodecIDs); ++i) { | 670 for (size_t i = 0; i < arraysize(kAmbiguousCodecIDs); ++i) { |
| 677 string_to_codec_map_[kAmbiguousCodecIDs[i].codec_id] = | 671 string_to_codec_map_[kAmbiguousCodecIDs[i].codec_id] = |
| 678 CodecEntry(kAmbiguousCodecIDs[i].codec, true); | 672 CodecEntry(kAmbiguousCodecIDs[i].codec, true); |
| 679 } | 673 } |
| 680 | 674 |
| 681 // Initialize the strict supported media types. | 675 // Initialize the strict supported media types. |
| 682 for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) { | 676 for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) { |
| 683 std::vector<std::string> mime_type_codecs; | 677 std::vector<std::string> mime_type_codecs; |
| 684 ParseCodecString(format_codec_mappings[i].codecs_list, | 678 ParseCodecString( |
| 685 &mime_type_codecs, | 679 format_codec_mappings[i].codecs_list, &mime_type_codecs, false); |
| 686 false); | |
| 687 | 680 |
| 688 CodecSet codecs; | 681 CodecSet codecs; |
| 689 for (size_t j = 0; j < mime_type_codecs.size(); ++j) { | 682 for (size_t j = 0; j < mime_type_codecs.size(); ++j) { |
| 690 Codec codec = INVALID_CODEC; | 683 Codec codec = INVALID_CODEC; |
| 691 bool is_ambiguous = true; | 684 bool is_ambiguous = true; |
| 692 CHECK(StringToCodec(mime_type_codecs[j], &codec, &is_ambiguous)); | 685 CHECK(StringToCodec(mime_type_codecs[j], &codec, &is_ambiguous)); |
| 693 DCHECK(!is_ambiguous); | 686 DCHECK(!is_ambiguous); |
| 694 codecs.insert(codec); | 687 codecs.insert(codec); |
| 695 } | 688 } |
| 696 | 689 |
| 697 strict_format_map_[format_codec_mappings[i].mime_type] = codecs; | 690 strict_format_map_[format_codec_mappings[i].mime_type] = codecs; |
| 698 } | 691 } |
| 699 } | 692 } |
| 700 | 693 |
| 701 bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const { | 694 bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const { |
| 702 return image_map_.find(mime_type) != image_map_.end(); | 695 return image_map_.find(mime_type) != image_map_.end(); |
| 703 } | 696 } |
| 704 | 697 |
| 705 bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const { | 698 bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const { |
| 706 return media_map_.find(mime_type) != media_map_.end(); | 699 return media_map_.find(mime_type) != media_map_.end(); |
| 707 } | 700 } |
| 708 | 701 |
| 709 bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const { | 702 bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const { |
| 710 return non_image_map_.find(mime_type) != non_image_map_.end() || | 703 return non_image_map_.find(mime_type) != non_image_map_.end() || |
| 711 (mime_type.compare(0, 5, "text/") == 0 && | 704 (mime_type.compare(0, 5, "text/") == 0 && |
| 712 !IsUnsupportedTextMimeType(mime_type)) || | 705 !IsUnsupportedTextMimeType(mime_type)) || |
| 713 (mime_type.compare(0, 12, "application/") == 0 && | 706 (mime_type.compare(0, 12, "application/") == 0 && |
| 714 MatchesMimeType("application/*+json", mime_type)); | 707 MatchesMimeType("application/*+json", mime_type)); |
| 715 } | 708 } |
| 716 | 709 |
| 717 bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const { | 710 bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const { |
| 718 return unsupported_text_map_.find(mime_type) != unsupported_text_map_.end(); | 711 return unsupported_text_map_.find(mime_type) != unsupported_text_map_.end(); |
| 719 } | 712 } |
| 720 | 713 |
| 721 bool MimeUtil::IsSupportedJavascriptMimeType( | 714 bool MimeUtil::IsSupportedJavascriptMimeType( |
| 722 const std::string& mime_type) const { | 715 const std::string& mime_type) const { |
| 723 return javascript_map_.find(mime_type) != javascript_map_.end(); | 716 return javascript_map_.find(mime_type) != javascript_map_.end(); |
| 724 } | 717 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 735 // parameters in the pattern, the match is a success. | 728 // parameters in the pattern, the match is a success. |
| 736 bool MatchesMimeTypeParameters(const std::string& mime_type_pattern, | 729 bool MatchesMimeTypeParameters(const std::string& mime_type_pattern, |
| 737 const std::string& mime_type) { | 730 const std::string& mime_type) { |
| 738 const std::string::size_type semicolon = mime_type_pattern.find(';'); | 731 const std::string::size_type semicolon = mime_type_pattern.find(';'); |
| 739 const std::string::size_type test_semicolon = mime_type.find(';'); | 732 const std::string::size_type test_semicolon = mime_type.find(';'); |
| 740 if (semicolon != std::string::npos) { | 733 if (semicolon != std::string::npos) { |
| 741 if (test_semicolon == std::string::npos) | 734 if (test_semicolon == std::string::npos) |
| 742 return false; | 735 return false; |
| 743 | 736 |
| 744 std::vector<std::string> pattern_parameters; | 737 std::vector<std::string> pattern_parameters; |
| 745 base::SplitString(mime_type_pattern.substr(semicolon + 1), | 738 base::SplitString( |
| 746 ';', &pattern_parameters); | 739 mime_type_pattern.substr(semicolon + 1), ';', &pattern_parameters); |
| 747 | 740 |
| 748 std::vector<std::string> test_parameters; | 741 std::vector<std::string> test_parameters; |
| 749 base::SplitString(mime_type.substr(test_semicolon + 1), | 742 base::SplitString( |
| 750 ';', &test_parameters); | 743 mime_type.substr(test_semicolon + 1), ';', &test_parameters); |
| 751 | 744 |
| 752 sort(pattern_parameters.begin(), pattern_parameters.end()); | 745 sort(pattern_parameters.begin(), pattern_parameters.end()); |
| 753 sort(test_parameters.begin(), test_parameters.end()); | 746 sort(test_parameters.begin(), test_parameters.end()); |
| 754 std::vector<std::string> difference = | 747 std::vector<std::string> difference = |
| 755 base::STLSetDifference<std::vector<std::string> >(pattern_parameters, | 748 base::STLSetDifference<std::vector<std::string> >(pattern_parameters, |
| 756 test_parameters); | 749 test_parameters); |
| 757 return difference.size() == 0; | 750 return difference.size() == 0; |
| 758 } | 751 } |
| 759 return true; | 752 return true; |
| 760 } | 753 } |
| 761 | 754 |
| 762 // This comparison handles absolute maching and also basic | 755 // This comparison handles absolute maching and also basic |
| 763 // wildcards. The plugin mime types could be: | 756 // wildcards. The plugin mime types could be: |
| 764 // application/x-foo | 757 // application/x-foo |
| 765 // application/* | 758 // application/* |
| 766 // application/*+xml | 759 // application/*+xml |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 804 | 797 |
| 805 if (!right.empty() && | 798 if (!right.empty() && |
| 806 base_type.rfind(right) != base_type.length() - right.length()) | 799 base_type.rfind(right) != base_type.length() - right.length()) |
| 807 return false; | 800 return false; |
| 808 | 801 |
| 809 return MatchesMimeTypeParameters(mime_type_pattern, mime_type); | 802 return MatchesMimeTypeParameters(mime_type_pattern, mime_type); |
| 810 } | 803 } |
| 811 | 804 |
| 812 // See http://www.iana.org/assignments/media-types/media-types.xhtml | 805 // See http://www.iana.org/assignments/media-types/media-types.xhtml |
| 813 static const char* legal_top_level_types[] = { | 806 static const char* legal_top_level_types[] = { |
| 814 "application", | 807 "application", |
| 815 "audio", | 808 "audio", |
| 816 "example", | 809 "example", |
| 817 "image", | 810 "image", |
| 818 "message", | 811 "message", |
| 819 "model", | 812 "model", |
| 820 "multipart", | 813 "multipart", |
| 821 "text", | 814 "text", |
| 822 "video", | 815 "video", |
| 823 }; | 816 }; |
| 824 | 817 |
| 825 bool MimeUtil::ParseMimeTypeWithoutParameter( | 818 bool MimeUtil::ParseMimeTypeWithoutParameter(const std::string& type_string, |
| 826 const std::string& type_string, | 819 std::string* top_level_type, |
| 827 std::string* top_level_type, | 820 std::string* subtype) const { |
| 828 std::string* subtype) const { | |
| 829 std::vector<std::string> components; | 821 std::vector<std::string> components; |
| 830 base::SplitString(type_string, '/', &components); | 822 base::SplitString(type_string, '/', &components); |
| 831 if (components.size() != 2 || | 823 if (components.size() != 2 || !HttpUtil::IsToken(components[0]) || |
| 832 !HttpUtil::IsToken(components[0]) || | |
| 833 !HttpUtil::IsToken(components[1])) | 824 !HttpUtil::IsToken(components[1])) |
| 834 return false; | 825 return false; |
| 835 | 826 |
| 836 if (top_level_type) | 827 if (top_level_type) |
| 837 *top_level_type = components[0]; | 828 *top_level_type = components[0]; |
| 838 if (subtype) | 829 if (subtype) |
| 839 *subtype = components[1]; | 830 *subtype = components[1]; |
| 840 return true; | 831 return true; |
| 841 } | 832 } |
| 842 | 833 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 SupportsType MimeUtil::IsSupportedStrictMediaMimeType( | 881 SupportsType MimeUtil::IsSupportedStrictMediaMimeType( |
| 891 const std::string& mime_type, | 882 const std::string& mime_type, |
| 892 const std::vector<std::string>& codecs) const { | 883 const std::vector<std::string>& codecs) const { |
| 893 StrictMappings::const_iterator it_strict_map = | 884 StrictMappings::const_iterator it_strict_map = |
| 894 strict_format_map_.find(mime_type); | 885 strict_format_map_.find(mime_type); |
| 895 if (it_strict_map == strict_format_map_.end()) | 886 if (it_strict_map == strict_format_map_.end()) |
| 896 return codecs.empty() ? MayBeSupported : IsNotSupported; | 887 return codecs.empty() ? MayBeSupported : IsNotSupported; |
| 897 | 888 |
| 898 if (it_strict_map->second.empty()) { | 889 if (it_strict_map->second.empty()) { |
| 899 // We get here if the mimetype does not expect a codecs parameter. | 890 // We get here if the mimetype does not expect a codecs parameter. |
| 900 return (codecs.empty() && IsDefaultCodecSupported(mime_type)) ? | 891 return (codecs.empty() && IsDefaultCodecSupported(mime_type)) |
| 901 IsSupported : IsNotSupported; | 892 ? IsSupported |
| 893 : IsNotSupported; |
| 902 } | 894 } |
| 903 | 895 |
| 904 if (codecs.empty()) { | 896 if (codecs.empty()) { |
| 905 // We get here if the mimetype expects to get a codecs parameter, | 897 // We get here if the mimetype expects to get a codecs parameter, |
| 906 // but didn't get one. If |mime_type| does not have a default codec | 898 // but didn't get one. If |mime_type| does not have a default codec |
| 907 // the best we can do is say "maybe" because we don't have enough | 899 // the best we can do is say "maybe" because we don't have enough |
| 908 // information. | 900 // information. |
| 909 Codec default_codec = INVALID_CODEC; | 901 Codec default_codec = INVALID_CODEC; |
| 910 if (!GetDefaultCodec(mime_type, &default_codec)) | 902 if (!GetDefaultCodec(mime_type, &default_codec)) |
| 911 return MayBeSupported; | 903 return MayBeSupported; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 938 // 1 bit: constraint_set3_flag : ignored here. | 930 // 1 bit: constraint_set3_flag : ignored here. |
| 939 // 4 bits: reserved : required to be 0 here. | 931 // 4 bits: reserved : required to be 0 here. |
| 940 // | 932 // |
| 941 // The spec indicates other ways, not implemented here, that a |profile_str| | 933 // The spec indicates other ways, not implemented here, that a |profile_str| |
| 942 // can indicate a baseline conforming decoder is sufficient for decode in Annex | 934 // can indicate a baseline conforming decoder is sufficient for decode in Annex |
| 943 // A.2.1: "[profile_idc not necessarily 0x42] with constraint_set0_flag set and | 935 // A.2.1: "[profile_idc not necessarily 0x42] with constraint_set0_flag set and |
| 944 // in which level_idc and constraint_set3_flag represent a level less than or | 936 // in which level_idc and constraint_set3_flag represent a level less than or |
| 945 // equal to the specified level." | 937 // equal to the specified level." |
| 946 static bool IsValidH264BaselineProfile(const std::string& profile_str) { | 938 static bool IsValidH264BaselineProfile(const std::string& profile_str) { |
| 947 uint32 constraint_set_bits; | 939 uint32 constraint_set_bits; |
| 948 if (profile_str.size() != 4 || | 940 if (profile_str.size() != 4 || profile_str[0] != '4' || |
| 949 profile_str[0] != '4' || | 941 profile_str[1] != '2' || profile_str[3] != '0' || |
| 950 profile_str[1] != '2' || | |
| 951 profile_str[3] != '0' || | |
| 952 !base::HexStringToUInt(base::StringPiece(profile_str.c_str() + 2, 1), | 942 !base::HexStringToUInt(base::StringPiece(profile_str.c_str() + 2, 1), |
| 953 &constraint_set_bits)) { | 943 &constraint_set_bits)) { |
| 954 return false; | 944 return false; |
| 955 } | 945 } |
| 956 | 946 |
| 957 return constraint_set_bits >= 8; | 947 return constraint_set_bits >= 8; |
| 958 } | 948 } |
| 959 | 949 |
| 960 static bool IsValidH264Level(const std::string& level_str) { | 950 static bool IsValidH264Level(const std::string& level_str) { |
| 961 uint32 level; | 951 uint32 level; |
| 962 if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level)) | 952 if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level)) |
| 963 return false; | 953 return false; |
| 964 | 954 |
| 965 // Valid levels taken from Table A-1 in ISO-14496-10. | 955 // Valid levels taken from Table A-1 in ISO-14496-10. |
| 966 // Essentially |level_str| is toHex(10 * level). | 956 // Essentially |level_str| is toHex(10 * level). |
| 967 return ((level >= 10 && level <= 13) || | 957 return ((level >= 10 && level <= 13) || (level >= 20 && level <= 22) || |
| 968 (level >= 20 && level <= 22) || | 958 (level >= 30 && level <= 32) || (level >= 40 && level <= 42) || |
| 969 (level >= 30 && level <= 32) || | |
| 970 (level >= 40 && level <= 42) || | |
| 971 (level >= 50 && level <= 51)); | 959 (level >= 50 && level <= 51)); |
| 972 } | 960 } |
| 973 | 961 |
| 974 // Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10. | 962 // Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10. |
| 975 // avc1.42y0xx, y >= 8 - H.264 Baseline | 963 // avc1.42y0xx, y >= 8 - H.264 Baseline |
| 976 // avc1.4D40xx - H.264 Main | 964 // avc1.4D40xx - H.264 Main |
| 977 // avc1.6400xx - H.264 High | 965 // avc1.6400xx - H.264 High |
| 978 // | 966 // |
| 979 // avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to | 967 // avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to |
| 980 // signal H.264 Baseline. For example, the idc_level, profile_idc and | 968 // signal H.264 Baseline. For example, the idc_level, profile_idc and |
| 981 // constraint_set3_flag pieces may explicitly require decoder to conform to | 969 // constraint_set3_flag pieces may explicitly require decoder to conform to |
| 982 // baseline profile at the specified level (see Annex A and constraint_set0 in | 970 // baseline profile at the specified level (see Annex A and constraint_set0 in |
| 983 // ISO-14496-10). | 971 // ISO-14496-10). |
| 984 static bool ParseH264CodecID(const std::string& codec_id, | 972 static bool ParseH264CodecID(const std::string& codec_id, |
| 985 MimeUtil::Codec* codec, | 973 MimeUtil::Codec* codec, |
| 986 bool* is_ambiguous) { | 974 bool* is_ambiguous) { |
| 987 // Make sure we have avc1.xxxxxx or avc3.xxxxxx | 975 // Make sure we have avc1.xxxxxx or avc3.xxxxxx |
| 988 if (codec_id.size() != 11 || | 976 if (codec_id.size() != 11 || (!StartsWithASCII(codec_id, "avc1.", true) && |
| 989 (!StartsWithASCII(codec_id, "avc1.", true) && | 977 !StartsWithASCII(codec_id, "avc3.", true))) { |
| 990 !StartsWithASCII(codec_id, "avc3.", true))) { | |
| 991 return false; | 978 return false; |
| 992 } | 979 } |
| 993 | 980 |
| 994 std::string profile = StringToUpperASCII(codec_id.substr(5, 4)); | 981 std::string profile = StringToUpperASCII(codec_id.substr(5, 4)); |
| 995 if (IsValidH264BaselineProfile(profile)) { | 982 if (IsValidH264BaselineProfile(profile)) { |
| 996 *codec = MimeUtil::H264_BASELINE; | 983 *codec = MimeUtil::H264_BASELINE; |
| 997 } else if (profile == "4D40") { | 984 } else if (profile == "4D40") { |
| 998 *codec = MimeUtil::H264_MAIN; | 985 *codec = MimeUtil::H264_MAIN; |
| 999 } else if (profile == "6400") { | 986 } else if (profile == "6400") { |
| 1000 *codec = MimeUtil::H264_HIGH; | 987 *codec = MimeUtil::H264_HIGH; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1057 case VP9: | 1044 case VP9: |
| 1058 case THEORA: | 1045 case THEORA: |
| 1059 return false; | 1046 return false; |
| 1060 } | 1047 } |
| 1061 | 1048 |
| 1062 return true; | 1049 return true; |
| 1063 } | 1050 } |
| 1064 | 1051 |
| 1065 bool MimeUtil::GetDefaultCodec(const std::string& mime_type, | 1052 bool MimeUtil::GetDefaultCodec(const std::string& mime_type, |
| 1066 Codec* default_codec) const { | 1053 Codec* default_codec) const { |
| 1067 if (mime_type == "audio/mpeg" || | 1054 if (mime_type == "audio/mpeg" || mime_type == "audio/mp3" || |
| 1068 mime_type == "audio/mp3" || | |
| 1069 mime_type == "audio/x-mp3") { | 1055 mime_type == "audio/x-mp3") { |
| 1070 *default_codec = MimeUtil::MP3; | 1056 *default_codec = MimeUtil::MP3; |
| 1071 return true; | 1057 return true; |
| 1072 } | 1058 } |
| 1073 | 1059 |
| 1074 return false; | 1060 return false; |
| 1075 } | 1061 } |
| 1076 | 1062 |
| 1077 | |
| 1078 bool MimeUtil::IsDefaultCodecSupported(const std::string& mime_type) const { | 1063 bool MimeUtil::IsDefaultCodecSupported(const std::string& mime_type) const { |
| 1079 Codec default_codec = Codec::INVALID_CODEC; | 1064 Codec default_codec = Codec::INVALID_CODEC; |
| 1080 if (!GetDefaultCodec(mime_type, &default_codec)) | 1065 if (!GetDefaultCodec(mime_type, &default_codec)) |
| 1081 return false; | 1066 return false; |
| 1082 return IsCodecSupported(default_codec); | 1067 return IsCodecSupported(default_codec); |
| 1083 } | 1068 } |
| 1084 | 1069 |
| 1085 //---------------------------------------------------------------------------- | 1070 //---------------------------------------------------------------------------- |
| 1086 // Wrappers for the singleton | 1071 // Wrappers for the singleton |
| 1087 //---------------------------------------------------------------------------- | 1072 //---------------------------------------------------------------------------- |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1164 void ParseCodecString(const std::string& codecs, | 1149 void ParseCodecString(const std::string& codecs, |
| 1165 std::vector<std::string>* codecs_out, | 1150 std::vector<std::string>* codecs_out, |
| 1166 const bool strip) { | 1151 const bool strip) { |
| 1167 g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip); | 1152 g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip); |
| 1168 } | 1153 } |
| 1169 | 1154 |
| 1170 namespace { | 1155 namespace { |
| 1171 | 1156 |
| 1172 // From http://www.w3schools.com/media/media_mimeref.asp and | 1157 // From http://www.w3schools.com/media/media_mimeref.asp and |
| 1173 // http://plugindoc.mozdev.org/winmime.php | 1158 // http://plugindoc.mozdev.org/winmime.php |
| 1174 static const char* const kStandardImageTypes[] = { | 1159 static const char* const kStandardImageTypes[] = {"image/bmp", |
| 1175 "image/bmp", | 1160 "image/cis-cod", |
| 1176 "image/cis-cod", | 1161 "image/gif", |
| 1177 "image/gif", | 1162 "image/ief", |
| 1178 "image/ief", | 1163 "image/jpeg", |
| 1179 "image/jpeg", | 1164 "image/webp", |
| 1180 "image/webp", | 1165 "image/pict", |
| 1181 "image/pict", | 1166 "image/pipeg", |
| 1182 "image/pipeg", | 1167 "image/png", |
| 1183 "image/png", | 1168 "image/svg+xml", |
| 1184 "image/svg+xml", | 1169 "image/tiff", |
| 1185 "image/tiff", | 1170 "image/vnd.microsoft.icon", |
| 1186 "image/vnd.microsoft.icon", | 1171 "image/x-cmu-raster", |
| 1187 "image/x-cmu-raster", | 1172 "image/x-cmx", |
| 1188 "image/x-cmx", | 1173 "image/x-icon", |
| 1189 "image/x-icon", | 1174 "image/x-portable-anymap", |
| 1190 "image/x-portable-anymap", | 1175 "image/x-portable-bitmap", |
| 1191 "image/x-portable-bitmap", | 1176 "image/x-portable-graymap", |
| 1192 "image/x-portable-graymap", | 1177 "image/x-portable-pixmap", |
| 1193 "image/x-portable-pixmap", | 1178 "image/x-rgb", |
| 1194 "image/x-rgb", | 1179 "image/x-xbitmap", |
| 1195 "image/x-xbitmap", | 1180 "image/x-xpixmap", |
| 1196 "image/x-xpixmap", | 1181 "image/x-xwindowdump"}; |
| 1197 "image/x-xwindowdump" | 1182 static const char* const kStandardAudioTypes[] = {"audio/aac", |
| 1198 }; | 1183 "audio/aiff", |
| 1199 static const char* const kStandardAudioTypes[] = { | 1184 "audio/amr", |
| 1200 "audio/aac", | 1185 "audio/basic", |
| 1201 "audio/aiff", | 1186 "audio/midi", |
| 1202 "audio/amr", | 1187 "audio/mp3", |
| 1203 "audio/basic", | 1188 "audio/mp4", |
| 1204 "audio/midi", | 1189 "audio/mpeg", |
| 1205 "audio/mp3", | 1190 "audio/mpeg3", |
| 1206 "audio/mp4", | 1191 "audio/ogg", |
| 1207 "audio/mpeg", | 1192 "audio/vorbis", |
| 1208 "audio/mpeg3", | 1193 "audio/wav", |
| 1209 "audio/ogg", | 1194 "audio/webm", |
| 1210 "audio/vorbis", | 1195 "audio/x-m4a", |
| 1211 "audio/wav", | 1196 "audio/x-ms-wma", |
| 1212 "audio/webm", | 1197 "audio/vnd.rn-realaudio", |
| 1213 "audio/x-m4a", | 1198 "audio/vnd.wave"}; |
| 1214 "audio/x-ms-wma", | 1199 static const char* const kStandardVideoTypes[] = {"video/avi", |
| 1215 "audio/vnd.rn-realaudio", | 1200 "video/divx", |
| 1216 "audio/vnd.wave" | 1201 "video/flc", |
| 1217 }; | 1202 "video/mp4", |
| 1218 static const char* const kStandardVideoTypes[] = { | 1203 "video/mpeg", |
| 1219 "video/avi", | 1204 "video/ogg", |
| 1220 "video/divx", | 1205 "video/quicktime", |
| 1221 "video/flc", | 1206 "video/sd-video", |
| 1222 "video/mp4", | 1207 "video/webm", |
| 1223 "video/mpeg", | 1208 "video/x-dv", |
| 1224 "video/ogg", | 1209 "video/x-m4v", |
| 1225 "video/quicktime", | 1210 "video/x-mpeg", |
| 1226 "video/sd-video", | 1211 "video/x-ms-asf", |
| 1227 "video/webm", | 1212 "video/x-ms-wmv"}; |
| 1228 "video/x-dv", | |
| 1229 "video/x-m4v", | |
| 1230 "video/x-mpeg", | |
| 1231 "video/x-ms-asf", | |
| 1232 "video/x-ms-wmv" | |
| 1233 }; | |
| 1234 | 1213 |
| 1235 struct StandardType { | 1214 struct StandardType { |
| 1236 const char* leading_mime_type; | 1215 const char* leading_mime_type; |
| 1237 const char* const* standard_types; | 1216 const char* const* standard_types; |
| 1238 size_t standard_types_len; | 1217 size_t standard_types_len; |
| 1239 }; | 1218 }; |
| 1240 static const StandardType kStandardTypes[] = { | 1219 static const StandardType kStandardTypes[] = { |
| 1241 { "image/", kStandardImageTypes, arraysize(kStandardImageTypes) }, | 1220 {"image/", kStandardImageTypes, arraysize(kStandardImageTypes)}, |
| 1242 { "audio/", kStandardAudioTypes, arraysize(kStandardAudioTypes) }, | 1221 {"audio/", kStandardAudioTypes, arraysize(kStandardAudioTypes)}, |
| 1243 { "video/", kStandardVideoTypes, arraysize(kStandardVideoTypes) }, | 1222 {"video/", kStandardVideoTypes, arraysize(kStandardVideoTypes)}, |
| 1244 { NULL, NULL, 0 } | 1223 {NULL, NULL, 0}}; |
| 1245 }; | |
| 1246 | 1224 |
| 1247 void GetExtensionsFromHardCodedMappings( | 1225 void GetExtensionsFromHardCodedMappings( |
| 1248 const MimeInfo* mappings, | 1226 const MimeInfo* mappings, |
| 1249 size_t mappings_len, | 1227 size_t mappings_len, |
| 1250 const std::string& leading_mime_type, | 1228 const std::string& leading_mime_type, |
| 1251 base::hash_set<base::FilePath::StringType>* extensions) { | 1229 base::hash_set<base::FilePath::StringType>* extensions) { |
| 1252 base::FilePath::StringType extension; | 1230 base::FilePath::StringType extension; |
| 1253 for (size_t i = 0; i < mappings_len; ++i) { | 1231 for (size_t i = 0; i < mappings_len; ++i) { |
| 1254 if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) { | 1232 if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) { |
| 1255 std::vector<string> this_extensions; | 1233 std::vector<string> this_extensions; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1285 extensions); | 1263 extensions); |
| 1286 | 1264 |
| 1287 GetExtensionsFromHardCodedMappings(secondary_mappings, | 1265 GetExtensionsFromHardCodedMappings(secondary_mappings, |
| 1288 arraysize(secondary_mappings), | 1266 arraysize(secondary_mappings), |
| 1289 leading_mime_type, | 1267 leading_mime_type, |
| 1290 extensions); | 1268 extensions); |
| 1291 } | 1269 } |
| 1292 | 1270 |
| 1293 // Note that the elements in the source set will be appended to the target | 1271 // Note that the elements in the source set will be appended to the target |
| 1294 // vector. | 1272 // vector. |
| 1295 template<class T> | 1273 template <class T> |
| 1296 void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) { | 1274 void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) { |
| 1297 size_t old_target_size = target->size(); | 1275 size_t old_target_size = target->size(); |
| 1298 target->resize(old_target_size + source->size()); | 1276 target->resize(old_target_size + source->size()); |
| 1299 size_t i = 0; | 1277 size_t i = 0; |
| 1300 for (typename base::hash_set<T>::iterator iter = source->begin(); | 1278 for (typename base::hash_set<T>::iterator iter = source->begin(); |
| 1301 iter != source->end(); ++iter, ++i) | 1279 iter != source->end(); |
| 1280 ++iter, ++i) |
| 1302 (*target)[old_target_size + i] = *iter; | 1281 (*target)[old_target_size + i] = *iter; |
| 1303 } | 1282 } |
| 1304 } | 1283 } |
| 1305 | 1284 |
| 1306 void GetExtensionsForMimeType( | 1285 void GetExtensionsForMimeType( |
| 1307 const std::string& unsafe_mime_type, | 1286 const std::string& unsafe_mime_type, |
| 1308 std::vector<base::FilePath::StringType>* extensions) { | 1287 std::vector<base::FilePath::StringType>* extensions) { |
| 1309 if (unsafe_mime_type == "*/*" || unsafe_mime_type == "*") | 1288 if (unsafe_mime_type == "*/*" || unsafe_mime_type == "*") |
| 1310 return; | 1289 return; |
| 1311 | 1290 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1367 // Don't create a map, there is only one entry in the table, | 1346 // Don't create a map, there is only one entry in the table, |
| 1368 // except on Android. | 1347 // except on Android. |
| 1369 for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) { | 1348 for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) { |
| 1370 if (mime_type == net::supported_certificate_types[i].mime_type) | 1349 if (mime_type == net::supported_certificate_types[i].mime_type) |
| 1371 return net::supported_certificate_types[i].cert_type; | 1350 return net::supported_certificate_types[i].cert_type; |
| 1372 } | 1351 } |
| 1373 return CERTIFICATE_MIME_TYPE_UNKNOWN; | 1352 return CERTIFICATE_MIME_TYPE_UNKNOWN; |
| 1374 } | 1353 } |
| 1375 | 1354 |
| 1376 bool IsSupportedCertificateMimeType(const std::string& mime_type) { | 1355 bool IsSupportedCertificateMimeType(const std::string& mime_type) { |
| 1377 CertificateMimeType file_type = | 1356 CertificateMimeType file_type = GetCertificateMimeTypeForMimeType(mime_type); |
| 1378 GetCertificateMimeTypeForMimeType(mime_type); | |
| 1379 return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN; | 1357 return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN; |
| 1380 } | 1358 } |
| 1381 | 1359 |
| 1382 void AddMultipartValueForUpload(const std::string& value_name, | 1360 void AddMultipartValueForUpload(const std::string& value_name, |
| 1383 const std::string& value, | 1361 const std::string& value, |
| 1384 const std::string& mime_boundary, | 1362 const std::string& mime_boundary, |
| 1385 const std::string& content_type, | 1363 const std::string& content_type, |
| 1386 std::string* post_data) { | 1364 std::string* post_data) { |
| 1387 DCHECK(post_data); | 1365 DCHECK(post_data); |
| 1388 // First line is the boundary. | 1366 // First line is the boundary. |
| 1389 post_data->append("--" + mime_boundary + "\r\n"); | 1367 post_data->append("--" + mime_boundary + "\r\n"); |
| 1390 // Next line is the Content-disposition. | 1368 // Next line is the Content-disposition. |
| 1391 post_data->append("Content-Disposition: form-data; name=\"" + | 1369 post_data->append("Content-Disposition: form-data; name=\"" + value_name + |
| 1392 value_name + "\"\r\n"); | 1370 "\"\r\n"); |
| 1393 if (!content_type.empty()) { | 1371 if (!content_type.empty()) { |
| 1394 // If Content-type is specified, the next line is that. | 1372 // If Content-type is specified, the next line is that. |
| 1395 post_data->append("Content-Type: " + content_type + "\r\n"); | 1373 post_data->append("Content-Type: " + content_type + "\r\n"); |
| 1396 } | 1374 } |
| 1397 // Leave an empty line and append the value. | 1375 // Leave an empty line and append the value. |
| 1398 post_data->append("\r\n" + value + "\r\n"); | 1376 post_data->append("\r\n" + value + "\r\n"); |
| 1399 } | 1377 } |
| 1400 | 1378 |
| 1401 void AddMultipartFinalDelimiterForUpload(const std::string& mime_boundary, | 1379 void AddMultipartFinalDelimiterForUpload(const std::string& mime_boundary, |
| 1402 std::string* post_data) { | 1380 std::string* post_data) { |
| 1403 DCHECK(post_data); | 1381 DCHECK(post_data); |
| 1404 post_data->append("--" + mime_boundary + "--\r\n"); | 1382 post_data->append("--" + mime_boundary + "--\r\n"); |
| 1405 } | 1383 } |
| 1406 | 1384 |
| 1407 } // namespace net | 1385 } // namespace net |
| OLD | NEW |