Commit cd6993de authored by idanan@chromium.org's avatar idanan@chromium.org

Error diagnostics for Blacklist IO

For now, as with other extension errors, these are not i18n'd.

The blacklist loading error is though because it is most like
an error to be shown to end users.

BUG=16932
TEST=none

Review URL: http://codereview.chromium.org/173357

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25895 0039d316-1c4b-4281-b951-d872f2087c98
parent c17fe94b
......@@ -4953,6 +4953,18 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_BLACKLIST_BLOCKED_REFERRER" desc="Referrer sending was blacklisted.">
Referrer not sent
</message>
<message name="IDS_BLACKLIST_ERROR_LOADING_TITLE" desc="Title of the dialog shown when the privacy blacklist cannot be loaded.">
Privacy Blacklist Error
</message>
<message name="IDS_BLACKLIST_ERROR_LOADING_TEXT" desc="Text of the dialog shown when the privacy blacklist cannot be loaded.">
Your privacy blacklists failed to load.
</message>
<message name="IDS_BLACKLIST_ERROR_LOADING_CONTINUE" desc="Continue button text when blacklist cannot be loaded.">
Continue
</message>
<message name="IDS_BLACKLIST_ERROR_LOADING_EXIT" desc="Exit button text when the privacy blacklist cannot be loaded.">
Exit
</message>
<!-- ProcessSingleton -->
<message name="IDS_PROFILE_IN_USE_LINUX" desc="Message shown when the browser cannot start because the profile is in use on a different host.">
......
......@@ -39,6 +39,7 @@
#include "chrome/browser/net/metadata_url_request.h"
#include "chrome/browser/net/sdch_dictionary_fetcher.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/privacy_blacklist/blacklist.h"
#include "chrome/browser/process_singleton.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
......@@ -96,6 +97,7 @@
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/rlz/rlz.h"
#include "chrome/browser/views/blacklist_error_dialog.h"
#include "chrome/browser/views/user_data_dir_dialog.h"
#include "chrome/common/env_vars.h"
#include "chrome/installer/util/helper.h"
......@@ -558,6 +560,18 @@ int BrowserMain(const MainFunctionParams& parameters) {
return ResultCodes::NORMAL_EXIT;
}
if (profile->GetBlacklist() && !profile->GetBlacklist()->is_good()) {
// TODO(idanan): Enable this for other platforms once the dispatching
// support code has been ported. See ifdefs in message_loop.h.
#if defined(OS_WIN)
bool accepted = BlacklistErrorDialog::RunBlacklistErrorDialog();
if (!accepted)
return ResultCodes::NORMAL_EXIT;
#else
return ResultCodes::NORMAL_EXIT;
#endif
}
PrefService* user_prefs = profile->GetPrefs();
DCHECK(user_prefs);
......
......@@ -5,6 +5,7 @@
#include "chrome/browser/privacy_blacklist/blacklist.h"
#include <algorithm>
#include <limits>
#include <string>
#include "base/file_path.h"
......@@ -159,35 +160,50 @@ void Blacklist::Match::AddEntry(const Entry* entry) {
entries_.push_back(entry);
}
Blacklist::Blacklist(const FilePath& file) {
Blacklist::Blacklist(const FilePath& file) : is_good_(false) {
// No blacklist, nothing to load.
if (file.value().empty())
return;
BlacklistStoreInput input(file_util::OpenFile(file, "rb"));
FILE* fp = file_util::OpenFile(file, "rb");
if (fp == NULL)
return;
BlacklistStoreInput input(fp);
// Read the providers
std::size_t n = input.ReadNumProviders();
if (n == std::numeric_limits<uint32>::max())
return;
providers_.reserve(n);
std::string name;
std::string url;
for (std::size_t i = 0; i < n; ++i) {
input.ReadProvider(&name, &url);
if (!input.ReadProvider(&name, &url))
return;
providers_.push_back(new Provider(name.c_str(), url.c_str()));
}
// Read the entries
n = input.ReadNumEntries();
if (n == std::numeric_limits<uint32>::max())
return;
std::string pattern;
unsigned int attributes, provider;
std::vector<std::string> types;
for (unsigned int i = 0; i < n; ++i) {
input.ReadEntry(&pattern, &attributes, &types, &provider);
if (!input.ReadEntry(&pattern, &attributes, &types, &provider))
return;
Entry* entry = new Entry(pattern, providers_[provider]);
entry->AddAttributes(attributes);
entry->SwapTypes(&types);
blacklist_.push_back(entry);
}
is_good_ = true;
}
Blacklist::~Blacklist() {
......@@ -202,6 +218,9 @@ Blacklist::~Blacklist() {
// Returns a pointer to the Blacklist-owned entry which matches the given
// URL. If no matching Entry is found, returns null.
Blacklist::Match* Blacklist::findMatch(const GURL& url) const {
if (!is_good_)
return NULL; // Don't attempt to find matches if the data is corrupt.
// Never match something which is not http, https or ftp.
// TODO(idanan): Investigate if this would be an inclusion test instead of an
// exclusion test and if there are other schemes to test for.
......
......@@ -158,6 +158,9 @@ class Blacklist {
// caller.
Match* findMatch(const GURL&) const;
// Returns true if the blacklist object is in good health.
bool is_good() const { return is_good_; }
// Helper to remove cookies from a header.
static std::string StripCookies(const std::string&);
......@@ -173,6 +176,8 @@ class Blacklist {
std::vector<Entry*> blacklist_;
std::vector<Provider*> providers_;
bool is_good_; // True if the blacklist was read successfully.
FRIEND_TEST(BlacklistTest, Generic);
FRIEND_TEST(BlacklistTest, PatternMatch);
DISALLOW_COPY_AND_ASSIGN(Blacklist);
......
......@@ -59,15 +59,19 @@ bool BlacklistIO::Read(const FilePath& file) {
// memory it would be the least of our worries. Typical blacklist files
// are less than 200K.
file_util::MemoryMappedFile input;
if (!input.Initialize(file) || !input.data())
if (!input.Initialize(file) || !input.data()) {
last_error_ = ASCIIToUTF16("File I/O error. Check path and permissions.");
return false;
}
const char* cur = reinterpret_cast<const char*>(input.data());
const char* end = cur + input.length();
// Check header.
if (!StartsWith(cur, end, header, arraysize(header)))
if (!StartsWith(cur, end, header, arraysize(header))) {
last_error_ = ASCIIToUTF16("Incorrect header.");
return false;
}
Blacklist::Provider* provider = new Blacklist::Provider;
providers_.push_back(provider);
......@@ -109,8 +113,10 @@ bool BlacklistIO::Read(const FilePath& file) {
std::string pattern(cur, skip);
cur = std::find_if(cur+pattern.size(), end, IsNotWhiteSpace());
if (!StartsWith(cur, end, arrow_tag, arraysize(arrow_tag)))
if (!StartsWith(cur, end, arrow_tag, arraysize(arrow_tag))) {
last_error_ = ASCIIToUTF16("Missing => in rule.");
return false;
}
scoped_ptr<Blacklist::Entry> entry(new Blacklist::Entry(pattern, provider));
......@@ -129,11 +135,18 @@ bool BlacklistIO::Read(const FilePath& file) {
if (tokenier.token_is_delim()) {
switch (*tokenier.token_begin()) {
case '(':
if (in_attribute) return false;
if (in_attribute) {
last_error_ =
ASCIIToUTF16("Unexpected ( in attribute parameters.");
return false;
}
in_attribute = true;
continue;
case ')':
if (!in_attribute) return false;
if (!in_attribute) {
last_error_ = ASCIIToUTF16("Unexpected ) in attribute list.");
return false;
}
in_attribute = false;
continue;
default:
......@@ -159,25 +172,43 @@ bool BlacklistIO::Read(const FilePath& file) {
bool BlacklistIO::Write(const FilePath& file) {
BlacklistStoreOutput output(file_util::OpenFile(file, "wb"));
if (!output.is_good()) {
last_error_ = ASCIIToUTF16("Error opening file for writing.");
return false;
}
// Output providers, give each one an index.
std::map<const Blacklist::Provider*, uint32> index;
uint32 current = 0;
output.ReserveProviders(providers_.size());
if (!output.ReserveProviders(providers_.size())) {
last_error_ = ASCIIToUTF16("Error writing to file.");
return false;
}
for (std::list<Blacklist::Provider*>::const_iterator i = providers_.begin();
i != providers_.end(); ++i, ++current) {
output.StoreProvider((*i)->name(), (*i)->url());
if (!output.StoreProvider((*i)->name(), (*i)->url())) {
last_error_ = ASCIIToUTF16("Error writing to file.");
return false;
}
index[*i] = current;
}
// Output entries, replacing the provider with its index.
output.ReserveEntries(blacklist_.size());
if (!output.ReserveEntries(blacklist_.size())) {
last_error_ = ASCIIToUTF16("Error writing to file.");
return false;
}
for (std::list<Blacklist::Entry*>::const_iterator i = blacklist_.begin();
i != blacklist_.end(); ++i) {
output.StoreEntry((*i)->pattern_,
(*i)->attributes_,
(*i)->types_,
index[(*i)->provider_]);
if (!output.StoreEntry((*i)->pattern_,
(*i)->attributes_,
(*i)->types_,
index[(*i)->provider_])) {
last_error_ = ASCIIToUTF16("Error writing to file.");
return false;
}
}
return true;
}
......@@ -7,6 +7,7 @@
#include <list>
#include "base/string16.h"
#include "chrome/browser/privacy_blacklist/blacklist.h"
class FilePath;
......@@ -24,6 +25,12 @@ class BlacklistIO {
// Writes a binary blacklist with aggregated entries for all read blacklists.
bool Write(const FilePath& path);
// Returns the text of the last occuring error. An empty string is returned
// if no such error happened.
const string16& last_error() const {
return last_error_;
}
private:
// Introspection functions, for testing purposes.
const std::list<Blacklist::Entry*>& blacklist() const {
......@@ -35,6 +42,7 @@ class BlacklistIO {
std::list<Blacklist::Entry*> blacklist_;
std::list<Blacklist::Provider*> providers_;
string16 last_error_; // Stores text of last error, empty if N/A.
FRIEND_TEST(BlacklistIOTest, Generic);
FRIEND_TEST(BlacklistIOTest, Combine);
......
......@@ -5,6 +5,7 @@
#include "chrome/browser/privacy_blacklist/blacklist_store.h"
#include <cstdio>
#include <limits>
#include "base/basictypes.h"
#include "base/file_util.h"
......@@ -14,83 +15,83 @@ namespace {
const char cookie[] = "GCPBL100";
const size_t kMaxBlockedTypes = 256;
const size_t kMaxStringSize = 8192;
}
void BlacklistStoreOutput::WriteUInt(uint32 i) {
if (fwrite(reinterpret_cast<char*>(&i), 1, sizeof(uint32), file_) !=
sizeof(uint32)) {
LOG(ERROR) << "fwrite failed to write uint32";
}
bool BlacklistStoreOutput::WriteUInt(uint32 i) {
return fwrite(reinterpret_cast<char*>(&i), 1, sizeof(uint32), file_) ==
sizeof(uint32);
}
void BlacklistStoreOutput::WriteString(const std::string& s) {
bool BlacklistStoreOutput::WriteString(const std::string& s) {
uint32 n = s.size();
if (fwrite(reinterpret_cast<char*>(&n), 1, sizeof(uint32), file_) !=
sizeof(uint32)) {
LOG(ERROR) << "fwrite failed to write string size";
}
if (fwrite(s.c_str(), 1, s.size(), file_) != s.size())
LOG(ERROR) << "fwrite failed to write string data";
return WriteUInt(n) && fwrite(s.c_str(), 1, n, file_) == n;
}
BlacklistStoreOutput::BlacklistStoreOutput(FILE* file) : file_(file) {
if (fwrite(cookie, 1, sizeof(cookie), file_) != sizeof(cookie))
LOG(ERROR) << "fwrite failed to write cookie";
BlacklistStoreOutput::BlacklistStoreOutput(FILE* file)
: file_(file), is_good_(false) {
is_good_ = fwrite(cookie, 1, sizeof(cookie), file_) == sizeof(cookie);
}
BlacklistStoreOutput::~BlacklistStoreOutput() {
file_util::CloseFile(file_);
}
void BlacklistStoreOutput::ReserveProviders(uint32 num) {
WriteUInt(num);
bool BlacklistStoreOutput::ReserveProviders(uint32 num) {
return WriteUInt(num);
}
void BlacklistStoreOutput::StoreProvider(const std::string& name,
bool BlacklistStoreOutput::StoreProvider(const std::string& name,
const std::string& url) {
WriteString(name);
WriteString(url);
return WriteString(name) && WriteString(url);
}
void BlacklistStoreOutput::ReserveEntries(uint32 num) {
WriteUInt(num);
bool BlacklistStoreOutput::ReserveEntries(uint32 num) {
return WriteUInt(num);
}
void BlacklistStoreOutput::StoreEntry(const std::string& pattern,
bool BlacklistStoreOutput::StoreEntry(const std::string& pattern,
uint32 attributes,
const std::vector<std::string>& types,
uint32 provider) {
WriteString(pattern);
WriteUInt(attributes);
WriteUInt(types.size());
for (uint32 i = 0; i < types.size(); ++i)
WriteString(types[i]);
WriteUInt(provider);
if (WriteString(pattern) &&
WriteUInt(attributes) &&
WriteUInt(types.size())) {
for (uint32 i = 0; i < types.size(); ++i) {
if (!WriteString(types[i]))
return false;
}
return WriteUInt(provider);
}
return false;
}
uint32 BlacklistStoreInput::ReadUInt() {
uint32 buf;
if (fread(&buf, 1, sizeof(uint32), file_) != sizeof(uint32))
return 0;
return std::numeric_limits<uint32>::max();
return buf;
}
std::string BlacklistStoreInput::ReadString() {
uint32 size = ReadUInt();
// Too long strings are not allowed.
if (size > 8192) {
// Too long strings are not allowed. Covers the case of ReadUInt failing.
if (size > kMaxStringSize) {
return std::string();
}
char buf[8192];
char buf[kMaxStringSize];
if (fread(buf, 1, size, file_) != size)
return std::string();
return std::string(buf, size);
}
BlacklistStoreInput::BlacklistStoreInput(FILE* file) : file_(file) {
fseek(file_, sizeof(cookie), SEEK_CUR);
BlacklistStoreInput::BlacklistStoreInput(FILE* file)
: file_(file), is_good_(false) {
is_good_ = !fseek(file_, sizeof(cookie), SEEK_CUR);
}
BlacklistStoreInput::~BlacklistStoreInput() {
......@@ -101,24 +102,40 @@ uint32 BlacklistStoreInput::ReadNumProviders() {
return ReadUInt();
}
void BlacklistStoreInput::ReadProvider(std::string* name, std::string* url) {
bool BlacklistStoreInput::ReadProvider(std::string* name, std::string* url) {
*name = ReadString();
if (name->empty())
return false;
*url = ReadString();
return !url->empty();
}
uint32 BlacklistStoreInput::ReadNumEntries() {
return ReadUInt();
}
void BlacklistStoreInput::ReadEntry(std::string* pattern,
bool BlacklistStoreInput::ReadEntry(std::string* pattern,
uint32* attributes,
std::vector<std::string>* types,
uint32* provider) {
*pattern = ReadString();
if (pattern->empty())
return false;
*attributes = ReadUInt();
if (*attributes == std::numeric_limits<uint32>::max())
return false;
if (uint32 n = ReadUInt()) {
while (n--)
types->push_back(ReadString());
if (n >= kMaxBlockedTypes)
return false;
while (n--) {
std::string type = ReadString();
if (type.empty())
return false;
types->push_back(type);
}
}
*provider = ReadUInt();
return *provider != std::numeric_limits<uint32>::max();
}
......@@ -13,8 +13,6 @@
class FilePath;
// TODO(idanan): Error handling needed. I/O errors can always happen!
////////////////////////////////////////////////////////////////////////////////
//
// Blacklist Binary Storage Output Class
......@@ -30,27 +28,31 @@ class BlacklistStoreOutput {
explicit BlacklistStoreOutput(FILE* file);
~BlacklistStoreOutput();
// Sets the number of providers stored.
void ReserveProviders(uint32);
// Returns true if the object initialized without error.
bool is_good() const { return is_good_; }
// Sets the number of providers stored. Returns true if successful.
bool ReserveProviders(uint32);
// Stores a provider.
void StoreProvider(const std::string& name, const std::string& url);
// Stores a provider. Returns true if successful.
bool StoreProvider(const std::string& name, const std::string& url);
// Sets the number of entries stored.
void ReserveEntries(uint32);
// Sets the number of entries stored. Returns true if successful.
bool ReserveEntries(uint32);
// Stores an entry.
void StoreEntry(const std::string& pattern,
// Stores an entry. Returns true if successful.
bool StoreEntry(const std::string& pattern,
uint32 attributes,
const std::vector<std::string>& types,
uint32 provider);
private:
// Writes basic types to the stream.
void WriteUInt(uint32);
void WriteString(const std::string&);
// Writes basic types to the stream. Returns true if successful.
bool WriteUInt(uint32);
bool WriteString(const std::string&);
FILE* file_;
bool is_good_;
DISALLOW_COPY_AND_ASSIGN(BlacklistStoreOutput);
};
......@@ -69,17 +71,20 @@ class BlacklistStoreInput {
explicit BlacklistStoreInput(FILE* file);
~BlacklistStoreInput();
// Returns true if this object initialized without error.
bool is_good() const { return is_good_; }
// Reads the number of providers.
uint32 ReadNumProviders();
// Reads a provider.
void ReadProvider(std::string* name, std::string* url);
// Reads a provider. Returns true on success.
bool ReadProvider(std::string* name, std::string* url);
// Reads the number of entries.
// Reads the number of entries. Returns true on success.
uint32 ReadNumEntries();
// Reads an entry.
void ReadEntry(std::string* pattern,
bool ReadEntry(std::string* pattern,
uint32* attributes,
std::vector<std::string>* types,
uint32* provider);
......@@ -89,6 +94,7 @@ class BlacklistStoreInput {
std::string ReadString();
FILE* file_;
bool is_good_;
DISALLOW_COPY_AND_ASSIGN(BlacklistStoreInput);
};
......
// Copyright (c) 2009 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 "chrome/browser/views/blacklist_error_dialog.h"
#include "app/l10n_util.h"
#include "app/message_box_flags.h"
#include "base/logging.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "views/controls/message_box_view.h"
#include "views/widget/widget.h"
#include "views/window/window.h"
// static
bool BlacklistErrorDialog::RunBlacklistErrorDialog() {
// When the window closes, it will delete itself.
BlacklistErrorDialog* dlg = new BlacklistErrorDialog;
MessageLoopForUI::current()->Run(dlg);
return dlg->accepted();
}
BlacklistErrorDialog::BlacklistErrorDialog()
: is_blocking_(true), accepted_(false) {
const int kDialogWidth = 400;
std::wstring message = l10n_util::GetString(IDS_BLACKLIST_ERROR_LOADING_TEXT);
box_view_ = new MessageBoxView(MessageBoxFlags::kIsConfirmMessageBox,
message.c_str(), std::wstring(), kDialogWidth);
views::Window::CreateChromeWindow(NULL, gfx::Rect(), this)->Show();
}
BlacklistErrorDialog::~BlacklistErrorDialog() {
}
std::wstring BlacklistErrorDialog::GetDialogButtonLabel(
MessageBoxFlags::DialogButton button) const {
switch (button) {
case MessageBoxFlags::DIALOGBUTTON_OK:
return l10n_util::GetString(IDS_BLACKLIST_ERROR_LOADING_CONTINUE);
case MessageBoxFlags::DIALOGBUTTON_CANCEL:
return l10n_util::GetString(IDS_BLACKLIST_ERROR_LOADING_EXIT);
}
return std::wstring();
}
std::wstring BlacklistErrorDialog::GetWindowTitle() const {
return l10n_util::GetString(IDS_BLACKLIST_ERROR_LOADING_TITLE);
}
void BlacklistErrorDialog::DeleteDelegate() {
delete this;
}
bool BlacklistErrorDialog::Accept() {
is_blocking_ = false;
accepted_ = true;
return true;
}
bool BlacklistErrorDialog::Cancel() {
is_blocking_ = false;
accepted_ = false;
return true;
}
views::View* BlacklistErrorDialog::GetContentsView() {
return box_view_;
}
bool BlacklistErrorDialog::Dispatch(const MSG& msg) {
TranslateMessage(&msg);
DispatchMessage(&msg);
return is_blocking_;
}
// Copyright (c) 2009 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.
//
// A dialog box that tells the user that we can't write to the specified user
// data directory. Provides the user a chance to pick a different directory.
#ifndef CHROME_BROWSER_BLACKLIST_ERROR_DIALOG_H_
#define CHROME_BROWSER_BLACKLIST_ERROR_DIALOG_H_
#include "base/message_loop.h"
#include "views/window/dialog_delegate.h"
class MessageBoxView;
namespace views {
class Window;
} // namespace views
class BlacklistErrorDialog : public views::DialogDelegate,
public MessageLoopForUI::Dispatcher {
public:
// Creates and runs a blacklist error dialog which is displayed modally
// to the user so that they know and acknowledge that their privacy is
// not protected.
static bool RunBlacklistErrorDialog();
virtual ~BlacklistErrorDialog();
bool accepted() const { return accepted_; }
// views::DialogDelegate Methods:
virtual std::wstring GetDialogButtonLabel(
MessageBoxFlags::DialogButton button) const;
virtual std::wstring GetWindowTitle() const;
virtual void DeleteDelegate();
virtual bool Accept();
virtual bool Cancel();
// views::WindowDelegate Methods:
virtual bool IsAlwaysOnTop() const { return false; }
virtual bool IsModal() const { return false; }
virtual views::View* GetContentsView();
// MessageLoop::Dispatcher Method:
virtual bool Dispatch(const MSG& msg);
private:
BlacklistErrorDialog();
MessageBoxView* box_view_;
// Used to keep track of whether or not to block the message loop (still
// waiting for the user to dismiss the dialog).
bool is_blocking_;
bool accepted_;
DISALLOW_COPY_AND_ASSIGN(BlacklistErrorDialog);
};
#endif // CHROME_BROWSER_BLACKLIST_ERROR_DIALOG_H_
......@@ -1911,6 +1911,8 @@
'browser/views/autocomplete/autocomplete_popup_win.h',
'browser/views/autocomplete/autocomplete_popup_gtk.cc',
'browser/views/autocomplete/autocomplete_popup_gtk.h',
'browser/views/blacklist_error_dialog.cc',
'browser/views/blacklist_error_dialog.h',
'browser/views/blocked_popup_container_view_win.cc',
'browser/views/blocked_popup_container_view_win.h',
'browser/views/bookmark_bar_view.cc',
......
......@@ -44,14 +44,15 @@ int IMAIN(int argc, ICHAR* argv[]) {
for (int current = 1; current < argc-1; ++current) {
FilePath input(argv[current]);
if (!io.Read(input)) {
ICERR << "Error reading input file " << argv[current] << "\n";
ICERR << "Error reading " << argv[current] << ":\n"
<< io.last_error() << "\n";
return -1;
}
}
FilePath output(argv[argc-1]);
if (!io.Write(output))
ICERR << "Error writing output file " << argv[2] << "\n";
ICERR << "Error writing " << argv[2] << ":\n" << io.last_error() << "\n";
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment