mime_util_unittest.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  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
  3. // found in the LICENSE file.
  4. #include "net/base/mime_util.h"
  5. #include <vector>
  6. #include "base/containers/contains.h"
  7. #include "base/strings/string_split.h"
  8. #include "base/strings/utf_string_conversions.h"
  9. #include "build/build_config.h"
  10. #include "build/chromeos_buildflags.h"
  11. #include "testing/gmock/include/gmock/gmock.h"
  12. #include "testing/gtest/include/gtest/gtest.h"
  13. namespace net {
  14. using testing::Contains;
  15. TEST(MimeUtilTest, GetWellKnownMimeTypeFromExtension) {
  16. // String: png\0css
  17. base::FilePath::StringType containsNullByte;
  18. containsNullByte.append(FILE_PATH_LITERAL("png"));
  19. containsNullByte.append(1, FILE_PATH_LITERAL('\0'));
  20. containsNullByte.append(FILE_PATH_LITERAL("css"));
  21. const struct {
  22. const base::FilePath::StringType extension;
  23. const char* const mime_type;
  24. } tests[] = {
  25. {FILE_PATH_LITERAL("png"), "image/png"},
  26. {FILE_PATH_LITERAL("PNG"), "image/png"},
  27. {FILE_PATH_LITERAL("css"), "text/css"},
  28. {FILE_PATH_LITERAL("pjp"), "image/jpeg"},
  29. {FILE_PATH_LITERAL("pjpeg"), "image/jpeg"},
  30. {FILE_PATH_LITERAL("json"), "application/json"},
  31. {FILE_PATH_LITERAL("js"), "text/javascript"},
  32. {FILE_PATH_LITERAL("webm"), "video/webm"},
  33. {FILE_PATH_LITERAL("weba"), "audio/webm"},
  34. {FILE_PATH_LITERAL("avif"), "image/avif"},
  35. {FILE_PATH_LITERAL("jxl"), "image/jxl"},
  36. {FILE_PATH_LITERAL("epub"), "application/epub+zip"},
  37. {FILE_PATH_LITERAL("apk"), "application/vnd.android.package-archive"},
  38. {FILE_PATH_LITERAL("cer"), "application/x-x509-ca-cert"},
  39. {FILE_PATH_LITERAL("crt"), "application/x-x509-ca-cert"},
  40. {FILE_PATH_LITERAL("zip"), "application/zip"},
  41. {FILE_PATH_LITERAL("ics"), "text/calendar"},
  42. {FILE_PATH_LITERAL("m3u8"), "application/x-mpegurl"},
  43. {FILE_PATH_LITERAL("csv"), "text/csv"},
  44. {FILE_PATH_LITERAL("not an extension / for sure"), nullptr},
  45. {containsNullByte, nullptr}};
  46. for (const auto& test : tests) {
  47. std::string mime_type;
  48. if (GetWellKnownMimeTypeFromExtension(test.extension, &mime_type))
  49. EXPECT_EQ(test.mime_type, mime_type);
  50. else
  51. EXPECT_EQ(test.mime_type, nullptr);
  52. }
  53. }
  54. TEST(MimeUtilTest, ExtensionTest) {
  55. // String: png\0css
  56. base::FilePath::StringType containsNullByte;
  57. containsNullByte.append(FILE_PATH_LITERAL("png"));
  58. containsNullByte.append(1, FILE_PATH_LITERAL('\0'));
  59. containsNullByte.append(FILE_PATH_LITERAL("css"));
  60. const struct {
  61. const base::FilePath::StringType extension;
  62. const std::vector<std::string> mime_types;
  63. } tests[] = {
  64. {FILE_PATH_LITERAL("png"), {"image/png"}},
  65. {FILE_PATH_LITERAL("PNG"), {"image/png"}},
  66. {FILE_PATH_LITERAL("css"), {"text/css"}},
  67. {FILE_PATH_LITERAL("pjp"), {"image/jpeg"}},
  68. {FILE_PATH_LITERAL("pjpeg"), {"image/jpeg"}},
  69. {FILE_PATH_LITERAL("json"), {"application/json"}},
  70. {FILE_PATH_LITERAL("js"), {"text/javascript"}},
  71. {FILE_PATH_LITERAL("webm"), {"video/webm"}},
  72. {FILE_PATH_LITERAL("weba"), {"audio/webm"}},
  73. {FILE_PATH_LITERAL("avif"), {"image/avif"}},
  74. {FILE_PATH_LITERAL("jxl"), {"image/jxl"}},
  75. #if BUILDFLAG(IS_CHROMEOS_ASH)
  76. // These are test cases for testing platform mime types on Chrome OS.
  77. {FILE_PATH_LITERAL("epub"), {"application/epub+zip"}},
  78. {FILE_PATH_LITERAL("apk"), {"application/vnd.android.package-archive"}},
  79. {FILE_PATH_LITERAL("cer"), {"application/x-x509-ca-cert"}},
  80. {FILE_PATH_LITERAL("crt"), {"application/x-x509-ca-cert"}},
  81. {FILE_PATH_LITERAL("zip"), {"application/zip"}},
  82. {FILE_PATH_LITERAL("ics"), {"text/calendar"}},
  83. #endif
  84. {FILE_PATH_LITERAL("m3u8"),
  85. {
  86. "application/x-mpegurl", // Chrome's secondary mapping.
  87. "audio/x-mpegurl", // https://crbug.com/1273061, system override for
  88. // android-arm[64]-test and Linux. Possibly more.
  89. "audio/mpegurl", // System override for mac.
  90. }},
  91. {FILE_PATH_LITERAL("csv"), {"text/csv"}},
  92. {FILE_PATH_LITERAL("not an extension / for sure"), {}},
  93. {containsNullByte, {}}
  94. };
  95. for (const auto& test : tests) {
  96. std::string mime_type;
  97. if (GetMimeTypeFromExtension(test.extension, &mime_type))
  98. EXPECT_THAT(test.mime_types, Contains(mime_type));
  99. else
  100. EXPECT_TRUE(test.mime_types.empty());
  101. }
  102. }
  103. // Behavior of GetPreferredExtensionForMimeType() is dependent on the host
  104. // platform since the latter can override the mapping from file extensions to
  105. // MIME types. The tests below would only work if the platform MIME mappings
  106. // don't have mappings for or has an agreeing mapping for each MIME type
  107. // mentioned.
  108. TEST(MimeUtilTest, GetPreferredExtensionForMimeType) {
  109. const struct {
  110. const std::string mime_type;
  111. const base::FilePath::StringType expected_extension;
  112. } kTestCases[] = {
  113. {"application/wasm", FILE_PATH_LITERAL("wasm")}, // Primary
  114. {"application/javascript", FILE_PATH_LITERAL("js")}, // Secondary
  115. {"text/javascript", FILE_PATH_LITERAL("js")}, // Primary
  116. {"video/webm", FILE_PATH_LITERAL("webm")}, // Primary
  117. };
  118. for (const auto& test : kTestCases) {
  119. base::FilePath::StringType extension;
  120. auto rv = GetPreferredExtensionForMimeType(test.mime_type, &extension);
  121. EXPECT_TRUE(rv);
  122. EXPECT_EQ(test.expected_extension, extension);
  123. }
  124. }
  125. TEST(MimeUtilTest, FileTest) {
  126. const struct {
  127. const base::FilePath::CharType* file_path;
  128. const char* const mime_type;
  129. bool valid;
  130. } tests[] = {
  131. {FILE_PATH_LITERAL("c:\\foo\\bar.css"), "text/css", true},
  132. {FILE_PATH_LITERAL("c:\\foo\\bar.CSS"), "text/css", true},
  133. {FILE_PATH_LITERAL("c:\\blah"), "", false},
  134. {FILE_PATH_LITERAL("/usr/local/bin/mplayer"), "", false},
  135. {FILE_PATH_LITERAL("/home/foo/bar.css"), "text/css", true},
  136. {FILE_PATH_LITERAL("/blah."), "", false},
  137. {FILE_PATH_LITERAL("c:\\blah."), "", false},
  138. };
  139. std::string mime_type;
  140. bool rv;
  141. for (const auto& test : tests) {
  142. rv = GetMimeTypeFromFile(base::FilePath(test.file_path), &mime_type);
  143. EXPECT_EQ(test.valid, rv);
  144. if (rv)
  145. EXPECT_EQ(test.mime_type, mime_type);
  146. }
  147. }
  148. TEST(MimeUtilTest, MatchesMimeType) {
  149. // MIME types are case insensitive.
  150. EXPECT_TRUE(MatchesMimeType("VIDEO/*", "video/x-mpeg"));
  151. EXPECT_TRUE(MatchesMimeType("video/*", "VIDEO/X-MPEG"));
  152. EXPECT_TRUE(MatchesMimeType("*", "video/x-mpeg"));
  153. EXPECT_TRUE(MatchesMimeType("video/*", "video/x-mpeg"));
  154. EXPECT_TRUE(MatchesMimeType("video/*", "video/*"));
  155. EXPECT_TRUE(MatchesMimeType("video/x-mpeg", "video/x-mpeg"));
  156. EXPECT_TRUE(MatchesMimeType("application/*+xml",
  157. "application/html+xml"));
  158. EXPECT_TRUE(MatchesMimeType("application/*+xml", "application/+xml"));
  159. EXPECT_TRUE(MatchesMimeType("application/*+json",
  160. "application/x-myformat+json"));
  161. EXPECT_TRUE(MatchesMimeType("aaa*aaa", "aaaaaa"));
  162. EXPECT_TRUE(MatchesMimeType("*", std::string()));
  163. EXPECT_FALSE(MatchesMimeType("video/", "video/x-mpeg"));
  164. EXPECT_FALSE(MatchesMimeType("VIDEO/", "Video/X-MPEG"));
  165. EXPECT_FALSE(MatchesMimeType(std::string(), "video/x-mpeg"));
  166. EXPECT_FALSE(MatchesMimeType(std::string(), std::string()));
  167. EXPECT_FALSE(MatchesMimeType("video/x-mpeg", std::string()));
  168. EXPECT_FALSE(MatchesMimeType("application/*+xml", "application/xml"));
  169. EXPECT_FALSE(MatchesMimeType("application/*+xml",
  170. "application/html+xmlz"));
  171. EXPECT_FALSE(MatchesMimeType("application/*+xml",
  172. "applcation/html+xml"));
  173. EXPECT_FALSE(MatchesMimeType("aaa*aaa", "aaaaa"));
  174. EXPECT_TRUE(MatchesMimeType("*", "video/x-mpeg;param=val"));
  175. EXPECT_TRUE(MatchesMimeType("*", "Video/X-MPEG;PARAM=VAL"));
  176. EXPECT_TRUE(MatchesMimeType("video/*", "video/x-mpeg;param=val"));
  177. EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/mpeg"));
  178. EXPECT_FALSE(MatchesMimeType("Video/*;PARAM=VAL", "VIDEO/Mpeg"));
  179. EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/mpeg;param=other"));
  180. EXPECT_TRUE(MatchesMimeType("video/*;param=val", "video/mpeg;param=val"));
  181. EXPECT_TRUE(MatchesMimeType("Video/*;PARAM=Val", "VIDEO/Mpeg;Param=Val"));
  182. EXPECT_FALSE(MatchesMimeType("Video/*;PARAM=VAL", "VIDEO/Mpeg;Param=Val"));
  183. EXPECT_TRUE(MatchesMimeType("video/x-mpeg", "video/x-mpeg;param=val"));
  184. EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val",
  185. "video/x-mpeg;param=val"));
  186. EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param2=val2",
  187. "video/x-mpeg;param=val"));
  188. EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param2=val2",
  189. "video/x-mpeg;param2=val"));
  190. EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val",
  191. "video/x-mpeg;param=val;param2=val2"));
  192. EXPECT_TRUE(MatchesMimeType("Video/X-Mpeg;Param=Val",
  193. "VIDEO/X-MPEG;PARAM=Val;PARAM2=val2"));
  194. EXPECT_TRUE(MatchesMimeType("Video/X-Mpeg;Param=VAL",
  195. "VIDEO/X-MPEG;PARAM=VAL;PARAM2=val2"));
  196. EXPECT_FALSE(MatchesMimeType("Video/X-Mpeg;Param=val",
  197. "VIDEO/X-MPEG;PARAM=VAL;PARAM2=val2"));
  198. EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param=VAL;param2=val2",
  199. "video/x-mpeg;param=val;param2=val2"));
  200. EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param2=val2;param=val",
  201. "video/x-mpeg;param=val;param2=val2"));
  202. EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param3=val3;param=val",
  203. "video/x-mpeg;param=val;param2=val2"));
  204. EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val ;param2=val2 ",
  205. "video/x-mpeg;param=val;param2=val2"));
  206. EXPECT_TRUE(MatchesMimeType("*/*;param=val", "video/x-mpeg;param=val"));
  207. EXPECT_FALSE(MatchesMimeType("*/*;param=val", "video/x-mpeg;param=val2"));
  208. EXPECT_TRUE(MatchesMimeType("*", "*"));
  209. EXPECT_TRUE(MatchesMimeType("*", "*/*"));
  210. EXPECT_TRUE(MatchesMimeType("*/*", "*/*"));
  211. EXPECT_TRUE(MatchesMimeType("*/*", "*"));
  212. EXPECT_TRUE(MatchesMimeType("video/*", "video/*"));
  213. EXPECT_FALSE(MatchesMimeType("video/*", "*/*"));
  214. EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/*"));
  215. EXPECT_TRUE(MatchesMimeType("video/*;param=val", "video/*;param=val"));
  216. EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/*;param=val2"));
  217. EXPECT_TRUE(MatchesMimeType("ab*cd", "abxxxcd"));
  218. EXPECT_TRUE(MatchesMimeType("ab*cd", "abx/xcd"));
  219. EXPECT_TRUE(MatchesMimeType("ab/*cd", "ab/xxxcd"));
  220. }
  221. TEST(MimeUtilTest, TestParseMimeType) {
  222. const struct {
  223. std::string type_str;
  224. std::string mime_type;
  225. base::StringPairs params;
  226. } tests[] = {
  227. // Simple tests.
  228. {"image/jpeg", "image/jpeg"},
  229. {"application/octet-stream;foo=bar;name=\"test.jpg\"",
  230. "application/octet-stream",
  231. {{"foo", "bar"}, {"name", "test.jpg"}}},
  232. // Quoted string parsing.
  233. {"t/s;name=\"t\\\\est\\\".jpg\"", "t/s", {{"name", "t\\est\".jpg"}}},
  234. {"t/s;name=\"test.jpg\"", "t/s", {{"name", "test.jpg"}}},
  235. {"t/s;name=\"test;jpg\"", "t/s", {{"name", "test;jpg"}}},
  236. // Lenient for no closing quote.
  237. {"t/s;name=\"test.jpg", "t/s", {{"name", "test.jpg"}}},
  238. {"t/s;name=\"ab\\\"", "t/s", {{"name", "ab\""}}},
  239. // Strip whitespace from start/end of mime_type.
  240. {" t/s", "t/s"},
  241. {"t/s ", "t/s"},
  242. {" t/s ", "t/s"},
  243. {"t/=", "t/="},
  244. // Generally ignore whitespace.
  245. {"t/s;a=1;b=2", "t/s", {{"a", "1"}, {"b", "2"}}},
  246. {"t/s ;a=1;b=2", "t/s", {{"a", "1"}, {"b", "2"}}},
  247. {"t/s; a=1;b=2", "t/s", {{"a", "1"}, {"b", "2"}}},
  248. // Special case, include whitespace after param name until equals.
  249. {"t/s;a =1;b=2", "t/s", {{"a ", "1"}, {"b", "2"}}},
  250. {"t/s;a= 1;b=2", "t/s", {{"a", "1"}, {"b", "2"}}},
  251. {"t/s;a=1 ;b=2", "t/s", {{"a", "1"}, {"b", "2"}}},
  252. {"t/s;a=1; b=2", "t/s", {{"a", "1"}, {"b", "2"}}},
  253. {"t/s; a = 1;b=2", "t/s", {{"a ", "1"}, {"b", "2"}}},
  254. // Do not trim whitespace from quoted-string param values.
  255. {"t/s;a=\" 1\";b=2", "t/s", {{"a", " 1"}, {"b", "2"}}},
  256. {"t/s;a=\"1 \";b=2", "t/s", {{"a", "1 "}, {"b", "2"}}},
  257. {"t/s;a=\" 1 \";b=2", "t/s", {{"a", " 1 "}, {"b", "2"}}},
  258. // Ignore incomplete params.
  259. {"t/s;a", "t/s", {}},
  260. {"t/s;a=", "t/s", {}},
  261. {"t/s;a=1;", "t/s", {{"a", "1"}}},
  262. {"t/s;a=1;b", "t/s", {{"a", "1"}}},
  263. {"t/s;a=1;b=", "t/s", {{"a", "1"}}},
  264. // Allow empty subtype.
  265. {"t/", "t/", {}},
  266. {"ts/", "ts/", {}},
  267. {"t/;", "t/", {}},
  268. {"t/ s", "t/", {}},
  269. // Questionable: allow anything as long as there is a slash somewhere.
  270. {"/ts", "/ts", {}},
  271. {"/s", "/s", {}},
  272. {"/", "/", {}},
  273. };
  274. for (const auto& test : tests) {
  275. std::string mime_type;
  276. base::StringPairs params;
  277. EXPECT_TRUE(ParseMimeType(test.type_str, &mime_type, &params));
  278. EXPECT_EQ(test.mime_type, mime_type);
  279. EXPECT_EQ(test.params, params);
  280. }
  281. for (auto* type_str : {
  282. // Must have slash in mime type.
  283. "",
  284. "ts",
  285. "t / s",
  286. }) {
  287. EXPECT_FALSE(ParseMimeType(type_str, nullptr, nullptr));
  288. }
  289. }
  290. TEST(MimeUtilTest, TestParseMimeTypeWithoutParameter) {
  291. std::string nonAscii("application/nonutf8");
  292. EXPECT_TRUE(ParseMimeTypeWithoutParameter(nonAscii, nullptr, nullptr));
  293. #if BUILDFLAG(IS_WIN)
  294. nonAscii.append(base::WideToUTF8(L"\u2603"));
  295. #else
  296. nonAscii.append("\u2603"); // unicode snowman
  297. #endif
  298. EXPECT_FALSE(ParseMimeTypeWithoutParameter(nonAscii, nullptr, nullptr));
  299. std::string top_level_type;
  300. std::string subtype;
  301. EXPECT_TRUE(ParseMimeTypeWithoutParameter(
  302. "application/mime", &top_level_type, &subtype));
  303. EXPECT_EQ("application", top_level_type);
  304. EXPECT_EQ("mime", subtype);
  305. // Various allowed subtype forms.
  306. EXPECT_TRUE(
  307. ParseMimeTypeWithoutParameter("application/json", nullptr, nullptr));
  308. EXPECT_TRUE(ParseMimeTypeWithoutParameter("application/x-suggestions+json",
  309. nullptr, nullptr));
  310. EXPECT_TRUE(
  311. ParseMimeTypeWithoutParameter("application/+json", nullptr, nullptr));
  312. // Upper case letters are allowed.
  313. EXPECT_TRUE(ParseMimeTypeWithoutParameter("text/mime", nullptr, nullptr));
  314. EXPECT_TRUE(ParseMimeTypeWithoutParameter("TEXT/mime", nullptr, nullptr));
  315. EXPECT_TRUE(ParseMimeTypeWithoutParameter("Text/mime", nullptr, nullptr));
  316. EXPECT_TRUE(ParseMimeTypeWithoutParameter("TeXt/mime", nullptr, nullptr));
  317. // Experimental types are also considered to be valid.
  318. EXPECT_TRUE(ParseMimeTypeWithoutParameter("x-video/mime", nullptr, nullptr));
  319. EXPECT_TRUE(ParseMimeTypeWithoutParameter("X-Video/mime", nullptr, nullptr));
  320. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text", nullptr, nullptr));
  321. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text/", nullptr, nullptr));
  322. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text/ ", nullptr, nullptr));
  323. EXPECT_FALSE(ParseMimeTypeWithoutParameter("te(xt/ ", nullptr, nullptr));
  324. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text/()plain", nullptr, nullptr));
  325. EXPECT_FALSE(ParseMimeTypeWithoutParameter("x-video", nullptr, nullptr));
  326. EXPECT_FALSE(ParseMimeTypeWithoutParameter("x-video/", nullptr, nullptr));
  327. EXPECT_FALSE(
  328. ParseMimeTypeWithoutParameter("application/a/b/c", nullptr, nullptr));
  329. // Test leading and trailing whitespace
  330. EXPECT_TRUE(ParseMimeTypeWithoutParameter(" text/plain", nullptr, nullptr));
  331. EXPECT_TRUE(ParseMimeTypeWithoutParameter("text/plain ", nullptr, nullptr));
  332. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text /plain", nullptr, nullptr));
  333. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text/ plain ", nullptr, nullptr));
  334. EXPECT_TRUE(ParseMimeTypeWithoutParameter("\ttext/plain", nullptr, nullptr));
  335. EXPECT_TRUE(ParseMimeTypeWithoutParameter("text/plain\t", nullptr, nullptr));
  336. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text\t/plain", nullptr, nullptr));
  337. EXPECT_FALSE(
  338. ParseMimeTypeWithoutParameter("text/\tplain ", nullptr, nullptr));
  339. EXPECT_TRUE(ParseMimeTypeWithoutParameter("\vtext/plain", nullptr, nullptr));
  340. EXPECT_TRUE(ParseMimeTypeWithoutParameter("text/plain\v", nullptr, nullptr));
  341. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text\v/plain", nullptr, nullptr));
  342. EXPECT_FALSE(
  343. ParseMimeTypeWithoutParameter("text/\vplain ", nullptr, nullptr));
  344. EXPECT_TRUE(ParseMimeTypeWithoutParameter("\rtext/plain", nullptr, nullptr));
  345. EXPECT_TRUE(ParseMimeTypeWithoutParameter("text/plain\r", nullptr, nullptr));
  346. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text\r/plain", nullptr, nullptr));
  347. EXPECT_FALSE(
  348. ParseMimeTypeWithoutParameter("text/\rplain ", nullptr, nullptr));
  349. EXPECT_TRUE(ParseMimeTypeWithoutParameter("\ntext/plain", nullptr, nullptr));
  350. EXPECT_TRUE(ParseMimeTypeWithoutParameter("text/plain\n", nullptr, nullptr));
  351. EXPECT_FALSE(ParseMimeTypeWithoutParameter("text\n/plain", nullptr, nullptr));
  352. EXPECT_FALSE(
  353. ParseMimeTypeWithoutParameter("text/\nplain ", nullptr, nullptr));
  354. }
  355. TEST(MimeUtilTest, TestIsValidTopLevelMimeType) {
  356. EXPECT_TRUE(IsValidTopLevelMimeType("application"));
  357. EXPECT_TRUE(IsValidTopLevelMimeType("audio"));
  358. EXPECT_TRUE(IsValidTopLevelMimeType("example"));
  359. EXPECT_TRUE(IsValidTopLevelMimeType("font"));
  360. EXPECT_TRUE(IsValidTopLevelMimeType("image"));
  361. EXPECT_TRUE(IsValidTopLevelMimeType("message"));
  362. EXPECT_TRUE(IsValidTopLevelMimeType("model"));
  363. EXPECT_TRUE(IsValidTopLevelMimeType("multipart"));
  364. EXPECT_TRUE(IsValidTopLevelMimeType("text"));
  365. EXPECT_TRUE(IsValidTopLevelMimeType("video"));
  366. EXPECT_TRUE(IsValidTopLevelMimeType("TEXT"));
  367. EXPECT_TRUE(IsValidTopLevelMimeType("Text"));
  368. EXPECT_TRUE(IsValidTopLevelMimeType("TeXt"));
  369. EXPECT_FALSE(IsValidTopLevelMimeType("mime"));
  370. EXPECT_FALSE(IsValidTopLevelMimeType(""));
  371. EXPECT_FALSE(IsValidTopLevelMimeType("/"));
  372. EXPECT_FALSE(IsValidTopLevelMimeType(" "));
  373. EXPECT_TRUE(IsValidTopLevelMimeType("x-video"));
  374. EXPECT_TRUE(IsValidTopLevelMimeType("X-video"));
  375. EXPECT_FALSE(IsValidTopLevelMimeType("x-"));
  376. }
  377. TEST(MimeUtilTest, TestGetExtensionsForMimeType) {
  378. const struct {
  379. const char* const mime_type;
  380. size_t min_expected_size;
  381. const char* const contained_result;
  382. bool no_matches;
  383. } tests[] = {
  384. {"text/plain", 2, "txt"},
  385. {"text/pl", 0, nullptr, true},
  386. {"*", 0, nullptr},
  387. {"", 0, nullptr, true},
  388. {"message/*", 1, "eml"},
  389. {"MeSsAge/*", 1, "eml"},
  390. {"message/", 0, nullptr, true},
  391. {"image/avif", 1, "avif"},
  392. {"image/jxl", 1, "jxl"},
  393. {"image/bmp", 1, "bmp"},
  394. {"video/*", 6, "mp4"},
  395. {"video/*", 6, "mpeg"},
  396. {"audio/*", 6, "oga"},
  397. {"aUDIo/*", 6, "wav"},
  398. };
  399. for (const auto& test : tests) {
  400. std::vector<base::FilePath::StringType> extensions;
  401. GetExtensionsForMimeType(test.mime_type, &extensions);
  402. ASSERT_LE(test.min_expected_size, extensions.size());
  403. if (test.no_matches)
  404. ASSERT_EQ(0u, extensions.size());
  405. if (test.contained_result) {
  406. // Convert ASCII to FilePath::StringType.
  407. base::FilePath::StringType contained_result(
  408. test.contained_result,
  409. test.contained_result + strlen(test.contained_result));
  410. bool found = base::Contains(extensions, contained_result);
  411. ASSERT_TRUE(found) << "Must find at least the contained result within "
  412. << test.mime_type;
  413. }
  414. }
  415. }
  416. TEST(MimeUtilTest, TestGenerateMimeMultipartBoundary) {
  417. std::string boundary1 = GenerateMimeMultipartBoundary();
  418. std::string boundary2 = GenerateMimeMultipartBoundary();
  419. // RFC 1341 says: the boundary parameter [...] consists of 1 to 70 characters.
  420. EXPECT_GE(70u, boundary1.size());
  421. EXPECT_GE(70u, boundary2.size());
  422. // RFC 1341 asks to: exercise care to choose a unique boundary.
  423. EXPECT_NE(boundary1, boundary2);
  424. ASSERT_LE(16u, boundary1.size());
  425. ASSERT_LE(16u, boundary2.size());
  426. // Expect that we don't pick '\0' character from the array/string
  427. // where we take the characters from.
  428. EXPECT_EQ(std::string::npos, boundary1.find('\0'));
  429. EXPECT_EQ(std::string::npos, boundary2.find('\0'));
  430. // Asserts below are not RFC 1341 requirements, but are here
  431. // to improve readability of generated MIME documents and to
  432. // try to preserve some aspects of the old boundary generation code.
  433. EXPECT_EQ("--", boundary1.substr(0, 2));
  434. EXPECT_EQ("--", boundary2.substr(0, 2));
  435. EXPECT_NE(std::string::npos, boundary1.find("MultipartBoundary"));
  436. EXPECT_NE(std::string::npos, boundary2.find("MultipartBoundary"));
  437. EXPECT_EQ("--", boundary1.substr(boundary1.size() - 2, 2));
  438. EXPECT_EQ("--", boundary2.substr(boundary2.size() - 2, 2));
  439. }
  440. TEST(MimeUtilTest, TestAddMultipartValueForUpload) {
  441. const char ref_output[] =
  442. "--boundary\r\nContent-Disposition: form-data;"
  443. " name=\"value name\"\r\nContent-Type: content type"
  444. "\r\n\r\nvalue\r\n"
  445. "--boundary\r\nContent-Disposition: form-data;"
  446. " name=\"value name\"\r\n\r\nvalue\r\n"
  447. "--boundary--\r\n";
  448. std::string post_data;
  449. AddMultipartValueForUpload("value name", "value", "boundary",
  450. "content type", &post_data);
  451. AddMultipartValueForUpload("value name", "value", "boundary",
  452. "", &post_data);
  453. AddMultipartFinalDelimiterForUpload("boundary", &post_data);
  454. EXPECT_STREQ(ref_output, post_data.c_str());
  455. }
  456. TEST(MimeUtilTest, TestAddMultipartValueForUploadWithFileName) {
  457. const char ref_output[] =
  458. "--boundary\r\nContent-Disposition: form-data;"
  459. " name=\"value name\"; filename=\"file name\"\r\nContent-Type: content "
  460. "type"
  461. "\r\n\r\nvalue\r\n"
  462. "--boundary\r\nContent-Disposition: form-data;"
  463. " name=\"value name\"; filename=\"file name\"\r\n\r\nvalue\r\n"
  464. "--boundary--\r\n";
  465. std::string post_data;
  466. AddMultipartValueForUploadWithFileName("value name", "file name", "value",
  467. "boundary", "content type",
  468. &post_data);
  469. AddMultipartValueForUploadWithFileName("value name", "file name", "value",
  470. "boundary", "", &post_data);
  471. AddMultipartFinalDelimiterForUpload("boundary", &post_data);
  472. EXPECT_STREQ(ref_output, post_data.c_str());
  473. }
  474. } // namespace net