diff options
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser_main.cc | 8 | ||||
-rw-r--r-- | chrome/browser/chromeos/external_cookie_handler.cc | 71 | ||||
-rw-r--r-- | chrome/browser/chromeos/external_cookie_handler.h | 49 | ||||
-rw-r--r-- | chrome/browser/chromeos/external_cookie_handler_unittest.cc | 152 | ||||
-rw-r--r-- | chrome/browser/chromeos/pipe_reader.cc | 17 | ||||
-rw-r--r-- | chrome/browser/chromeos/pipe_reader.h | 50 | ||||
-rw-r--r-- | chrome/browser/chromeos/pipe_reader_unittest.cc | 97 |
7 files changed, 444 insertions, 0 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index bb3d1c3..9b71bde 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -117,6 +117,10 @@ #include "views/focus/accelerator_handler.h" #endif +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/external_cookie_handler.h" +#endif + namespace Platform { void WillInitializeMainMessageLoop(const MainFunctionParams& parameters); @@ -793,6 +797,10 @@ int BrowserMain(const MainFunctionParams& parameters) { if (parsed_command_line.HasSwitch(switches::kEnableWebResources)) profile->InitWebResources(); +#if defined(OS_CHROMEOS) + ExternalCookieHandler::GetCookies(parsed_command_line, profile); +#endif + // Stat the directory with the inspector's files so that we can know if we // should display the entry in the context menu or not. browser_process->CheckForInspectorFiles(); diff --git a/chrome/browser/chromeos/external_cookie_handler.cc b/chrome/browser/chromeos/external_cookie_handler.cc new file mode 100644 index 0000000..e578395 --- /dev/null +++ b/chrome/browser/chromeos/external_cookie_handler.cc @@ -0,0 +1,71 @@ +// 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/chromeos/external_cookie_handler.h" + +#include "base/command_line.h" +#include "chrome/browser/chromeos/pipe_reader.h" +#include "chrome/browser/profile.h" +#include "chrome/common/chrome_switches.h" +#include "googleurl/src/gurl.h" +#include "net/base/cookie_store.h" +#include "net/url_request/url_request_context.h" + +void ExternalCookieHandler::GetCookies(const CommandLine& parsed_command_line, + Profile* profile) { + // If there are Google External SSO cookies, add them to the cookie store. + if (parsed_command_line.HasSwitch(switches::kCookiePipe)) { + std::string pipe_name = + WideToASCII(parsed_command_line.GetSwitchValue(switches::kCookiePipe)); + ExternalCookieHandler cookie_handler(new PipeReader(pipe_name)); + cookie_handler.HandleCookies( + profile->GetRequestContext()->cookie_store()); + } +} + +// static +const char ExternalCookieHandler::kGoogleAccountsUrl[] = + "https://www.google.com/a/google.com/acs"; + +const int kChunkSize = 256; + +// Reads up to a newline, or the end of the data, in increments of |chunk| +std::string ExternalCookieHandler::ReadLine(int chunk) { + std::string cookie_line = reader_->Read(chunk); + + // As long as it's not an empty line... + if (!cookie_line.empty()) { + // and there's no newline at the end... + while ('\n' != cookie_line[cookie_line.length() - 1]) { + // try to pull more data... + std::string piece = reader_->Read(chunk); + if (piece.empty()) // only stop if there's none left. + break; + else + cookie_line.append(piece); // otherwise, append and keep going. + } + } + + return cookie_line; +} + +bool ExternalCookieHandler::HandleCookies(net::CookieStore *cookie_store) { + DCHECK(cookie_store); + if (NULL != reader_.get()) { + GURL url(ExternalCookieHandler::kGoogleAccountsUrl); + net::CookieOptions options; + options.set_include_httponly(); + + // Each line we get is a cookie. Grab up to a newline, then put + // it in to the cookie jar. + std::string cookie_line = ReadLine(kChunkSize); + while (!cookie_line.empty()) { + if (!cookie_store->SetCookieWithOptions(url, cookie_line, options)) + return false; + cookie_line = ReadLine(kChunkSize); + } + return true; + } + return false; +} diff --git a/chrome/browser/chromeos/external_cookie_handler.h b/chrome/browser/chromeos/external_cookie_handler.h new file mode 100644 index 0000000..2886756 --- /dev/null +++ b/chrome/browser/chromeos/external_cookie_handler.h @@ -0,0 +1,49 @@ +// 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. + +#ifndef CHROME_BROWSER_CHROMEOS_EXTERNAL_COOKIE_HANDLER_H_ +#define CHROME_BROWSER_CHROMEOS_EXTERNAL_COOKIE_HANDLER_H_ + +#include <string> + +#include "base/scoped_ptr.h" +#include "chrome/browser/chromeos/pipe_reader.h" + +// Single sign on cookies for Google can be passed in over a +// pipe. If they've been sent, this reads them and adds them to the +// cookie store as session cookies. + +class CommandLine; +class Profile; +namespace net { +class CookieStore; +} + +class ExternalCookieHandler { + public: + // Takes ownsership of |reader|. + explicit ExternalCookieHandler(PipeReader *reader) : reader_(reader) {} + virtual ~ExternalCookieHandler() {} + + // Given a pipe to read cookies from, reads and adds them to |cookie_store|. + virtual bool HandleCookies(net::CookieStore *cookie_store); + + // Checks |parsed_command_line| for the --cookie-pipe; if found, reads + // cookies from the pipe and adds them to the cookie store found in |profile|. + static void GetCookies(const CommandLine& parsed_command_line, + Profile* profile); + + // The url with which we associate the read-in cookies. + static const char kGoogleAccountsUrl[]; + + private: + // Reads up to a newline, or the end of the data, in increments of |chunk|. + std::string ReadLine(int chunk); + + scoped_ptr<PipeReader> reader_; + + DISALLOW_COPY_AND_ASSIGN(ExternalCookieHandler); +}; + +#endif // CHROME_BROWSER_CHROMEOS_EXTERNAL_COOKIE_HANDLER_H_ diff --git a/chrome/browser/chromeos/external_cookie_handler_unittest.cc b/chrome/browser/chromeos/external_cookie_handler_unittest.cc new file mode 100644 index 0000000..014f52c --- /dev/null +++ b/chrome/browser/chromeos/external_cookie_handler_unittest.cc @@ -0,0 +1,152 @@ +// 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/chromeos/external_cookie_handler.h" + +#include <set> +#include <vector> + +#include "base/basictypes.h" +#include "base/time.h" +#include "googleurl/src/gurl.h" +#include "net/base/cookie_options.h" +#include "net/base/cookie_store.h" +#include "testing/gtest/include/gtest/gtest.h" + +typedef testing::Test ExternalCookieHandlerTest; + +static const std::string cookie1 = "coookie1\n"; +static const std::string cookie2 = "coookie2\n"; +static const std::string cookie3 = "coookie3"; + +class MockCookieStore : public net::CookieStore { + public: + MockCookieStore() : expected_url_(ExternalCookieHandler::kGoogleAccountsUrl) { + cookies_.insert(cookie1); + cookies_.insert(cookie2); + cookies_.insert(cookie3); + } + virtual ~MockCookieStore() {} + + virtual bool SetCookie(const GURL& url, const std::string& cookie_line) { + EXPECT_TRUE(false); + return true; + } + virtual bool SetCookieWithOptions(const GURL& url, + const std::string& cookie_line, + const net::CookieOptions& options) { + EXPECT_FALSE(options.exclude_httponly()); + EXPECT_EQ(expected_url_, url); + std::set<std::string>::iterator it; + it = cookies_.find(cookie_line); + bool has_cookie = cookies_.end() != it; + if (has_cookie) + cookies_.erase(it); + return has_cookie; + } + + virtual bool SetCookieWithCreationTime(const GURL& url, + const std::string& cookie_line, + const base::Time& creation_time) { + EXPECT_TRUE(false); + return true; + } + virtual bool SetCookieWithCreationTimeWithOptions( + const GURL& url, + const std::string& cookie_line, + const base::Time& creation_time, + const net::CookieOptions& options) { + EXPECT_TRUE(false); + return true; + } + + virtual void SetCookies(const GURL& url, + const std::vector<std::string>& cookies) { + EXPECT_TRUE(false); + } + virtual void SetCookiesWithOptions(const GURL& url, + const std::vector<std::string>& cookies, + const net::CookieOptions& options) { + EXPECT_TRUE(false); + } + + virtual std::string GetCookies(const GURL& url) { + EXPECT_TRUE(false); + return std::string(); + } + virtual std::string GetCookiesWithOptions(const GURL& url, + const net::CookieOptions& options) { + EXPECT_TRUE(false); + return std::string(); + } + + private: + std::set<std::string> cookies_; + const GURL expected_url_; + + DISALLOW_EVIL_CONSTRUCTORS(MockCookieStore); +}; + + +TEST_F(ExternalCookieHandlerTest, MockCookieStoreSanityTest) { + GURL url(ExternalCookieHandler::kGoogleAccountsUrl); + MockCookieStore cookie_store; + net::CookieOptions options; + options.set_include_httponly(); + EXPECT_TRUE(cookie_store.SetCookieWithOptions(url, cookie1, options)); + EXPECT_TRUE(cookie_store.SetCookieWithOptions(url, cookie2, options)); + EXPECT_TRUE(cookie_store.SetCookieWithOptions(url, cookie3, options)); + EXPECT_FALSE(cookie_store.SetCookieWithOptions(url, cookie1, options)); + EXPECT_FALSE(cookie_store.SetCookieWithOptions(url, cookie2, options)); + EXPECT_FALSE(cookie_store.SetCookieWithOptions(url, cookie3, options)); +} + +class MockReader : public PipeReader { + public: + explicit MockReader(const std::vector<std::string>& cookies) + : data_(cookies) { + } + + std::string Read(const uint32 bytes_to_read) { + std::string to_return; + if (!data_.empty()) { + to_return = data_.back(); + data_.pop_back(); + } + return to_return; + } + private: + std::vector<std::string> data_; +}; + +TEST_F(ExternalCookieHandlerTest, SuccessfulReadTest) { + GURL url(ExternalCookieHandler::kGoogleAccountsUrl); + + MockCookieStore cookie_store; + + std::vector<std::string> cookies; + cookies.push_back(cookie3); + cookies.push_back(cookie2); + cookies.push_back(cookie1); + MockReader *reader = new MockReader(cookies); + + ExternalCookieHandler handler(reader); // takes ownership. + EXPECT_TRUE(handler.HandleCookies(&cookie_store)); +} + +TEST_F(ExternalCookieHandlerTest, SuccessfulSlowReadTest) { + GURL url(ExternalCookieHandler::kGoogleAccountsUrl); + + MockCookieStore cookie_store; + + std::vector<std::string> cookies; + cookies.push_back(cookie3); + cookies.push_back(cookie2.substr(2)); + cookies.push_back(cookie2.substr(0, 2)); + cookies.push_back(cookie1); + MockReader *reader = new MockReader(cookies); + + ExternalCookieHandler handler(reader); // takes ownership. + EXPECT_TRUE(handler.HandleCookies(&cookie_store)); +} diff --git a/chrome/browser/chromeos/pipe_reader.cc b/chrome/browser/chromeos/pipe_reader.cc new file mode 100644 index 0000000..16b9f06 --- /dev/null +++ b/chrome/browser/chromeos/pipe_reader.cc @@ -0,0 +1,17 @@ +// 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/chromeos/pipe_reader.h" + +#include "base/scoped_ptr.h" + +std::string PipeReader::Read(const uint32 bytes_to_read) { + scoped_array<char> buffer(new char[bytes_to_read]); + if (pipe_ || (pipe_ = fopen(pipe_name_.c_str(), "r"))) { + const char* to_return = fgets(buffer.get(), bytes_to_read, pipe_); + if (to_return) + return to_return; // auto-coerced to a std::string. + } + return std::string(); +} diff --git a/chrome/browser/chromeos/pipe_reader.h b/chrome/browser/chromeos/pipe_reader.h new file mode 100644 index 0000000..d2a3bf2 --- /dev/null +++ b/chrome/browser/chromeos/pipe_reader.h @@ -0,0 +1,50 @@ +// 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. + +#ifndef CHROME_BROWSER_CHROMEOS_PIPE_READER_H_ +#define CHROME_BROWSER_CHROMEOS_PIPE_READER_H_ + +#include <fcntl.h> +#include <string> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "base/basictypes.h" + +// Given a named pipe, this class reads data from it and returns it as a string. +// Currently, we are sending login cookies from the Chrome OS login manager to +// Chrome over a named Unix pipe. We want to replace this with DBus, but +// would like to create a DBus wrapper library to use throughout Chrome OS +// first. This stopgap lets us get the infrastructure for passing credentials +// to Chrome in place, which will help clean up login jankiness, and also +// refactor our code as we await the DBus stuff. +// TODO(cmasone): get rid of this code and replace with DBus. + +class PipeReader { + public: + explicit PipeReader(const std::string& pipe_name) + : pipe_(NULL), + pipe_name_(pipe_name) { + } + virtual ~PipeReader() { + if (pipe_) + fclose(pipe_); + } + + // Reads data from the pipe up until either a '\n' or |bytes_to_read| bytes. + virtual std::string Read(const uint32 bytes_to_read); + + protected: + // For testing. + PipeReader() : pipe_(NULL) {} + + private: + FILE *pipe_; + std::string pipe_name_; + + DISALLOW_COPY_AND_ASSIGN(PipeReader); +}; + +#endif // CHROME_BROWSER_CHROMEOS_PIPE_READER_H_ diff --git a/chrome/browser/chromeos/pipe_reader_unittest.cc b/chrome/browser/chromeos/pipe_reader_unittest.cc new file mode 100644 index 0000000..6d674dd --- /dev/null +++ b/chrome/browser/chromeos/pipe_reader_unittest.cc @@ -0,0 +1,97 @@ +// 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/chromeos/pipe_reader.h" + +#include <errno.h> + +#include "testing/gtest/include/gtest/gtest.h" + +typedef testing::Test PipeReaderTest; + +TEST_F(PipeReaderTest, SuccessfulReadTest) { + std::string pipe_name("/tmp/MYFIFO"); + /* Create the FIFO if it does not exist */ + umask(0); + mknod(pipe_name.c_str(), S_IFIFO|0666, 0); + const char line[] = "foo"; + + pid_t pID = fork(); + if (pID == 0) { + int pipe = open(pipe_name.c_str(), O_WRONLY); + EXPECT_NE(pipe, -1) << strerror(errno); + write(pipe, line, strlen(line)); + close(pipe); + exit(1); + } else { + PipeReader reader(pipe_name); + // asking for more should still just return the amount that was written. + EXPECT_EQ(line, reader.Read(5 * strlen(line))); + } +} + +TEST_F(PipeReaderTest, SuccessfulMultiLineReadTest) { + std::string pipe_name("/tmp/TESTFIFO"); + /* Create the FIFO if it does not exist */ + umask(0); + mknod(pipe_name.c_str(), S_IFIFO|0666, 0); + const char foo[] = "foo"; + const char boo[] = "boo"; + std::string line(foo); + line.append("\n"); + line.append(boo); + line.append("\n"); + + pid_t pID = fork(); + if (pID == 0) { + int pipe = open(pipe_name.c_str(), O_WRONLY); + EXPECT_NE(pipe, -1) << strerror(errno); + write(pipe, line.c_str(), line.length()); + close(pipe); + exit(1); + } else { + PipeReader reader(pipe_name); + // asking for more should still just return the amount that was written. + std::string my_foo = reader.Read(5 * line.length()); + EXPECT_EQ(my_foo[my_foo.length() - 1], '\n'); + my_foo.resize(my_foo.length() - 1); + EXPECT_EQ(my_foo, foo); + + std::string my_boo = reader.Read(5 * line.length()); + EXPECT_EQ(my_boo[my_boo.length() - 1], '\n'); + my_boo.resize(my_boo.length() - 1); + EXPECT_EQ(my_boo, boo); + } +} + +TEST_F(PipeReaderTest, SuccessfulMultiLineReadNoEndingNewlineTest) { + std::string pipe_name("/tmp/TESTFIFO"); + /* Create the FIFO if it does not exist */ + umask(0); + mknod(pipe_name.c_str(), S_IFIFO|0666, 0); + const char foo[] = "foo"; + const char boo[] = "boo"; + std::string line(foo); + line.append("\n"); + line.append(boo); + + pid_t pID = fork(); + if (pID == 0) { + int pipe = open(pipe_name.c_str(), O_WRONLY); + EXPECT_NE(pipe, -1) << strerror(errno); + write(pipe, line.c_str(), line.length()); + close(pipe); + exit(1); + } else { + PipeReader reader(pipe_name); + // asking for more should still just return the amount that was written. + std::string my_foo = reader.Read(5 * line.length()); + EXPECT_EQ(my_foo[my_foo.length() - 1], '\n'); + my_foo.resize(my_foo.length() - 1); + EXPECT_EQ(my_foo, foo); + + std::string my_boo = reader.Read(5 * line.length()); + EXPECT_EQ(my_boo, boo); + } +} |