From 6153ad9d42b202335a534c72b6d72de0f74017ce Mon Sep 17 00:00:00 2001 From: "cristian.patrasciuc@gmail.com" Date: Fri, 27 Jul 2012 08:03:55 +0000 Subject: Added functionality such that on Linux, after downloading a file, the source URL and referrer URL are stored as extended file attributes. Also see http://www.freedesktop.org/wiki/CommonExtendedAttributes BUG=45903 TEST=content_unittests/file_metadata_unittest_linux.cc/FileMetadataLinuxTest Review URL: https://chromiumcodereview.appspot.com/10784007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148729 0039d316-1c4b-4281-b951-d872f2087c98 --- content/browser/download/base_file.cc | 5 + content/browser/download/file_metadata_linux.cc | 43 ++++++ content/browser/download/file_metadata_linux.h | 31 ++++ .../download/file_metadata_unittest_linux.cc | 165 +++++++++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 content/browser/download/file_metadata_linux.cc create mode 100644 content/browser/download/file_metadata_linux.h create mode 100644 content/browser/download/file_metadata_unittest_linux.cc (limited to 'content/browser/download') diff --git a/content/browser/download/base_file.cc b/content/browser/download/base_file.cc index 396ac33..786e78c 100644 --- a/content/browser/download/base_file.cc +++ b/content/browser/download/base_file.cc @@ -27,6 +27,8 @@ #include "content/browser/safe_util_win.h" #elif defined(OS_MACOSX) #include "content/browser/file_metadata_mac.h" +#elif defined(OS_LINUX) +#include "content/browser/download/file_metadata_linux.h" #endif using content::BrowserThread; @@ -470,6 +472,8 @@ void BaseFile::AnnotateWithSourceInformation() { referrer_url_); file_metadata::AddOriginMetadataToFile(full_path_, source_url_, referrer_url_); +#elif defined(OS_LINUX) + content::AddOriginMetadataToFile(full_path_, source_url_, referrer_url_); #endif } @@ -555,3 +559,4 @@ int64 BaseFile::CurrentSpeed() const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); return CurrentSpeedAtTime(base::TimeTicks::Now()); } + diff --git a/content/browser/download/file_metadata_linux.cc b/content/browser/download/file_metadata_linux.cc new file mode 100644 index 0000000..5beece5 --- /dev/null +++ b/content/browser/download/file_metadata_linux.cc @@ -0,0 +1,43 @@ +// Copyright (c) 2012 The Chromium 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 "content/browser/download/file_metadata_linux.h" + +#include +#include + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "googleurl/src/gurl.h" + +namespace content { + +const char kSourceURLAttrName[] = "user.xdg.origin.url"; +const char kReferrerURLAttrName[] = "user.xdg.referrer.url"; + +static void SetExtendedFileAttribute(const char* path, const char* name, + const char* value, size_t value_size, + int flags) { + int result = setxattr(path, name, value, value_size, flags); + if (result) { + DPLOG(ERROR) + << "Could not set extended attribute " << name << " on file " << path; + } +} + +void AddOriginMetadataToFile(const FilePath& file, const GURL& source, + const GURL& referrer) { + DCHECK(file_util::PathIsWritable(file)); + if (source.is_valid()) { + SetExtendedFileAttribute(file.value().c_str(), kSourceURLAttrName, + source.spec().c_str(), source.spec().length(), 0); + } + if (referrer.is_valid()) { + SetExtendedFileAttribute(file.value().c_str(), kReferrerURLAttrName, + referrer.spec().c_str(), referrer.spec().length(), 0); + } +} + +} // namespace file_metadata diff --git a/content/browser/download/file_metadata_linux.h b/content/browser/download/file_metadata_linux.h new file mode 100644 index 0000000..b735f6e --- /dev/null +++ b/content/browser/download/file_metadata_linux.h @@ -0,0 +1,31 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_DOWNLOAD_FILE_METADATA_LINUX_H_ +#define CONTENT_BROWSER_DOWNLOAD_FILE_METADATA_LINUX_H_ + +#include "content/common/content_export.h" + +class FilePath; +class GURL; + +namespace content { + +// The source URL attribute is part of the XDG standard. +// The referrer URL attribute is not part of the XDG standard, +// but it is used to keep the naming consistent. +// http://freedesktop.org/wiki/CommonExtendedAttributes +CONTENT_EXPORT extern const char kSourceURLAttrName[]; +CONTENT_EXPORT extern const char kReferrerURLAttrName[]; + +// Adds origin metadata to the file. +// |source| should be the source URL for the download, and |referrer| should be +// the URL the user initiated the download from. +CONTENT_EXPORT void AddOriginMetadataToFile(const FilePath& file, + const GURL& source, + const GURL& referrer); + +} // namespace file_metadata + +#endif // CONTENT_BROWSER_DOWNLOAD_FILE_METADATA_LINUX_H_ diff --git a/content/browser/download/file_metadata_unittest_linux.cc b/content/browser/download/file_metadata_unittest_linux.cc new file mode 100644 index 0000000..40ed3e5 --- /dev/null +++ b/content/browser/download/file_metadata_unittest_linux.cc @@ -0,0 +1,165 @@ +// Copyright (c) 2012 The Chromium 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 +#include +#include + +#include +#include +#include + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/scoped_temp_dir.h" +#include "base/string_split.h" +#include "content/browser/download/file_metadata_linux.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using std::istringstream; +using std::string; +using std::vector; + +class FileMetadataLinuxTest : public testing::Test { + public: + FileMetadataLinuxTest() + : source_url_("http://www.source.com"), + referrer_url_("http://www.referrer.com") {} + + const FilePath& test_file() const { + return test_file_; + } + + const GURL& source_url() const { + return source_url_; + } + + const GURL& referrer_url() const { + return referrer_url_; + } + + bool is_xattr_supported() const { + return is_xattr_supported_; + } + + protected: + virtual void SetUp() OVERRIDE { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_.path(), + &test_file_)); + int result = setxattr(test_file_.value().c_str(), + "user.test", "test", 4, 0); + is_xattr_supported_ = (!result) || (errno != ENOTSUP); + if (!is_xattr_supported_) { + LOG(INFO) << "Test will be skipped because extended attributes are not " + << "supported on this OS/file system."; + } + } + + void CheckExtendedAttributeValue(const string attr_name, + const string expected_value) const { + ssize_t len = getxattr(test_file().value().c_str(), attr_name.c_str(), + NULL, 0); + if (len <= static_cast(0)) { + FAIL() << "Attribute '" << attr_name << "' does not exist"; + } + char* buffer = new char[len]; + len = getxattr(test_file().value().c_str(), attr_name.c_str(), buffer, len); + EXPECT_EQ(expected_value.size(), static_cast(len)); + string real_value(buffer, len); + delete[] buffer; + EXPECT_EQ(expected_value, real_value); + } + + void GetExtendedAttributeNames(vector* attr_names) const { + ssize_t len = listxattr(test_file().value().c_str(), NULL, 0); + if (len <= static_cast(0)) return; + char* buffer = new char[len]; + len = listxattr(test_file().value().c_str(), buffer, len); + attr_names->clear(); + base::SplitString(string(buffer, len), '\0', attr_names); + delete[] buffer; + } + + void VerifyAttributesAreSetCorrectly() const { + vector attr_names; + GetExtendedAttributeNames(&attr_names); + + // Check if the attributes are set on the file + vector::const_iterator pos = find(attr_names.begin(), + attr_names.end(), content::kSourceURLAttrName); + EXPECT_NE(pos, attr_names.end()); + pos = find(attr_names.begin(), attr_names.end(), + content::kReferrerURLAttrName); + EXPECT_NE(pos, attr_names.end()); + + // Check if the attribute values are set correctly + CheckExtendedAttributeValue(content::kSourceURLAttrName, + source_url().spec()); + CheckExtendedAttributeValue(content::kReferrerURLAttrName, + referrer_url().spec()); + } + + private: + ScopedTempDir temp_dir_; + FilePath test_file_; + GURL source_url_; + GURL referrer_url_; + bool is_xattr_supported_; +}; + +TEST_F(FileMetadataLinuxTest, CheckMetadataSetCorrectly) { + if (!is_xattr_supported()) return; + content::AddOriginMetadataToFile(test_file(), source_url(), referrer_url()); + VerifyAttributesAreSetCorrectly(); +} + +TEST_F(FileMetadataLinuxTest, SetMetadataMultipleTimes) { + if (!is_xattr_supported()) return; + content::AddOriginMetadataToFile(test_file(), + GURL("http://www.dummy.com"), GURL("http://www.dummy.com")); + content::AddOriginMetadataToFile(test_file(), source_url(), referrer_url()); + VerifyAttributesAreSetCorrectly(); +} + +TEST_F(FileMetadataLinuxTest, InvalidSourceURLTest) { + if (!is_xattr_supported()) return; + GURL invalid_url; + vector attr_names; + content::AddOriginMetadataToFile(test_file(), invalid_url, referrer_url()); + GetExtendedAttributeNames(&attr_names); + EXPECT_EQ(attr_names.end(), find(attr_names.begin(), attr_names.end(), + content::kSourceURLAttrName)); + CheckExtendedAttributeValue(content::kReferrerURLAttrName, + referrer_url().spec()); +} + +TEST_F(FileMetadataLinuxTest, InvalidReferrerURLTest) { + if (!is_xattr_supported()) return; + GURL invalid_url; + vector attr_names; + content::AddOriginMetadataToFile(test_file(), source_url(), invalid_url); + GetExtendedAttributeNames(&attr_names); + EXPECT_EQ(attr_names.end(), find(attr_names.begin(), attr_names.end(), + content::kReferrerURLAttrName)); + CheckExtendedAttributeValue(content::kSourceURLAttrName, source_url().spec()); +} + +TEST_F(FileMetadataLinuxTest, InvalidURLsTest) { + if (!is_xattr_supported()) return; + GURL invalid_url; + vector attr_names; + content::AddOriginMetadataToFile(test_file(), invalid_url, invalid_url); + GetExtendedAttributeNames(&attr_names); + EXPECT_EQ(attr_names.end(), find(attr_names.begin(), attr_names.end(), + content::kSourceURLAttrName)); + EXPECT_EQ(attr_names.end(), find(attr_names.begin(), attr_names.end(), + content::kReferrerURLAttrName)); +} + +} // namespace -- cgit v1.1