blob: 7baf388de1c43f2e5ae2530b1349db61484d1378 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <string>
#include <vector>
#include <base/base64.h>
#include <base/check.h>
#include <base/files/scoped_temp_dir.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <gtest/gtest.h>
#include "vm_tools/garcon/mime_types_parser.h"
namespace vm_tools {
namespace garcon {
namespace {
// Test mime.cache files are generated using a process such as:
// mkdir -p /tmp/mimetest/packages
// cat <<EOF >> /tmp/mimetest/packages/application-x-foobar.xml
// <?xml version="1.0" encoding="UTF-8"?>
// <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
// <mime-type type="x/no-dot"><glob pattern="~"/></mime-type>
// <mime-type type="application/pdf"><glob pattern="*.pdf"/></mime-type>
// <mime-type type="text/plain"><glob pattern="*.txt"/></mime-type>
// <mime-type type="text/plain"><glob pattern="*.doc"/></mime-type>
// <mime-type type="text/plain"><glob pattern="*.foo"/></mime-type>
// <mime-type type="x/smile"><glob pattern="*.🙂🤩"/></mime-type>
// </mime-info>
// EOF
// update-mime-database /tmp/mimetest
// base64 -270 /tmp/mimetest/mime.cache
// See https://wiki.archlinux.org/title/XDG_MIME_Applications
static constexpr const char kTestMimeCacheB64[] =
"AAEAAgAAAGAAAABkAAAAaAAAAHgAAAGgAAABpAAAAbAAAAG0AAABuAAAAbx0ZXh0L3BsYW"
"luAAB+AAAAeC9uby1kb3QAAAAAYXBwbGljYXRpb24vcGRmAHgvc21pbGUAAAAAAAAAAAAA"
"AAABAAAAOAAAADwAAAAyAAAABQAAAIAAAABjAAAAAQAAALwAAABmAAAAAQAAAMgAAABvAA"
"AAAQAAANQAAAB0AAAAAQAAAOAAAfkpAAAAAQAAAOwAAABvAAAAAQAAAPgAAABkAAAAAQAA"
"AQQAAABvAAAAAQAAARAAAAB4AAAAAQAAARwAAfZCAAAAAQAAASgAAABkAAAAAQAAATQAAA"
"BwAAAAAQAAAUAAAABmAAAAAQAAAUwAAAB0AAAAAQAAAVgAAAAuAAAAAQAAAWQAAAAuAAAA"
"AQAAAXAAAAAuAAAAAQAAAXwAAAAuAAAAAQAAAYgAAAAuAAAAAQAAAZQAAAAAAAAAWAAAAD"
"IAAAAAAAAALAAAADIAAAAAAAAASAAAADIAAAAAAAAALAAAADIAAAAAAAAALAAAADIAAAAA"
"AAAAAAAAAAAAAAGwAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA=";
class MimeTypesParserTest : public ::testing::Test {
public:
MimeTypesParserTest() {
CHECK(temp_dir_.CreateUniqueTempDir());
mime_types_path_ = temp_dir_.GetPath().Append("mime.types");
}
MimeTypesParserTest(const MimeTypesParserTest&) = delete;
MimeTypesParserTest& operator=(const MimeTypesParserTest&) = delete;
~MimeTypesParserTest() override = default;
void WriteContents(const std::string& file_contents) {
EXPECT_EQ(file_contents.size(),
base::WriteFile(mime_types_path_, file_contents.c_str(),
file_contents.size()));
}
// Ensures that parsing fails when mime.cache file is modified such that
// |buf[pos] = c|.
void InvalidIf(std::string buf, int pos, char c) {
std::string s(buf);
s[pos] = c;
WriteContents(s);
MimeTypeMap map;
EXPECT_FALSE(ParseMimeTypes(TempFilePath(), &map));
}
std::string TempFilePath() const { return mime_types_path_.value(); }
private:
base::ScopedTempDir temp_dir_;
base::FilePath mime_types_path_;
};
} // namespace
TEST_F(MimeTypesParserTest, NonExistentFileFails) {
MimeTypeMap map;
EXPECT_FALSE(ParseMimeTypes("/invalid/filepath/foo", &map));
}
TEST_F(MimeTypesParserTest, ValidResult) {
MimeTypeMap map;
std::string buf;
base::Base64Decode(kTestMimeCacheB64, &buf);
WriteContents(buf);
EXPECT_TRUE(ParseMimeTypes(TempFilePath(), &map));
MimeTypeMap expected = {
{"pdf", "application/pdf"}, {"txt", "text/plain"},
{"doc", "text/plain"}, {"foo", "text/plain"},
{"🙂🤩", "x/smile"},
};
EXPECT_EQ(map, expected);
}
TEST_F(MimeTypesParserTest, Empty) {
MimeTypeMap map;
WriteContents("");
EXPECT_FALSE(ParseMimeTypes(TempFilePath(), &map));
}
// xxd /tmp/mimetest/mime.cache
// 00000000: 0001 0002 0000 0060 0000 0064 0000 0068 .......`...d...h
// 00000010: 0000 0078 0000 01a0 0000 01a4 0000 01b0 ...x............
// 00000020: 0000 01b4 0000 01b8 0000 01bc 7465 7874 ............text
// 00000030: 2f70 6c61 696e 0000 7e00 0000 782f 6e6f /plain..~...x/no
// 00000040: 2d64 6f74 0000 0000 6170 706c 6963 6174 -dot....applicat
// 00000050: 696f 6e2f 7064 6600 782f 736d 696c 6500 ion/pdf.x/smile.
// 00000060: 0000 0000 0000 0000 0000 0001 0000 0038 ...............8
// 00000070: 0000 003c 0000 0032 0000 0005 0000 0080 ...<...2........
// 00000080: 0000 0063 0000 0001 0000 00bc 0000 0066 ...c...........f
// 00000090: 0000 0001 0000 00c8 0000 006f 0000 0001 ...........o....
// 000000a0: 0000 00d4 0000 0074 0000 0001 0000 00e0 .......t........
// 000000b0: 0001 f929 0000 0001 0000 00ec 0000 006f ...)...........o
// 000000c0: 0000 0001 0000 00f8 0000 0064 0000 0001 ...........d....
// 000000d0: 0000 0104 0000 006f 0000 0001 0000 0110 .......o........
// 000000e0: 0000 0078 0000 0001 0000 011c 0001 f642 ...x...........B
// 000000f0: 0000 0001 0000 0128 0000 0064 0000 0001 .......(...d....
// 00000100: 0000 0134 0000 0070 0000 0001 0000 0140 ...4...p.......@
// 00000110: 0000 0066 0000 0001 0000 014c 0000 0074 ...f.......L...t
// 00000120: 0000 0001 0000 0158 0000 002e 0000 0001 .......X........
// 00000130: 0000 0164 0000 002e 0000 0001 0000 0170 ...d...........p
// 00000140: 0000 002e 0000 0001 0000 017c 0000 002e ...........|....
// 00000150: 0000 0001 0000 0188 0000 002e 0000 0001 ................
// 00000160: 0000 0194 0000 0000 0000 0058 0000 0032 ...........X...2
// 00000170: 0000 0000 0000 002c 0000 0032 0000 0000 .......,...2....
// 00000180: 0000 0048 0000 0032 0000 0000 0000 002c ...H...2.......,
// 00000190: 0000 0032 0000 0000 0000 002c 0000 0032 ...2.......,...2
// 000001a0: 0000 0000 0000 0000 0000 0000 0000 01b0 ................
// 000001b0: 0000 0000 0000 0000 0000 0000 0000 0004 ................
// 000001c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
TEST_F(MimeTypesParserTest, Invalid) {
std::string buf;
base::Base64Decode(kTestMimeCacheB64, &buf);
// ALIAS_LIST_OFFSET is uint32 at byte 4 = 0x60.
// Alias list offset inside header.
InvalidIf(buf, 7, 10);
// Alias list offset larger than file size.
InvalidIf(buf, 6, 0xff);
// Not null beore alias list.
InvalidIf(buf, 0x60 - 1, 'X');
// Misaligned offset for REVERSE_SUFFIX_TREE_OFFSET.
InvalidIf(buf, 0x13, 0x7a);
// N_ROOTS > kMaxUnicode (0x10ffff).
InvalidIf(buf, 0x79, 0x20);
InvalidIf(buf, 0xc1, 0x20);
// Node C > kMaxUnicode (0x10ffff).
InvalidIf(buf, 0x81, 0x20);
// Node N_CHILDREN > kMaxUnicode (0x10ffff).
InvalidIf(buf, 0x85, 0x20);
// Node FIRST_CHILD_OFFSET below tree offset.
InvalidIf(buf, 0x8b, 0x10);
InvalidIf(buf, 0xc7, 0x20);
// Node FIRST_CHILD_OFFSET beyond file size.
InvalidIf(buf, 0x8a, 0x20);
InvalidIf(buf, 0xc6, 0x20);
// Mime type offset below header.
InvalidIf(buf, 0x177, 0x10);
// Mime type offset above alias list.
InvalidIf(buf, 0x177, 0x60);
}
} // namespace garcon
} // namespace vm_tools