139 lines
3.9 KiB
C++
139 lines
3.9 KiB
C++
// Copyright 2015 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/ssl/ssl_key_logger_impl.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
#include "base/files/file_util.h"
|
|
#include "base/files/scoped_file.h"
|
|
#include "base/functional/bind.h"
|
|
#include "base/location.h"
|
|
#include "base/logging.h"
|
|
#include "base/memory/ref_counted.h"
|
|
#include "base/sequence_checker.h"
|
|
#include "base/synchronization/lock.h"
|
|
#include "base/task/sequenced_task_runner.h"
|
|
#include "base/task/task_traits.h"
|
|
#include "base/task/thread_pool.h"
|
|
#include "base/thread_annotations.h"
|
|
|
|
namespace net {
|
|
|
|
namespace {
|
|
// Bound the number of outstanding writes to bound memory usage. Some
|
|
// antiviruses point this at a pipe and then read too slowly. See
|
|
// https://crbug.com/566951 and https://crbug.com/914880.
|
|
static constexpr size_t kMaxOutstandingLines = 512;
|
|
} // namespace
|
|
|
|
// An object which performs the blocking file operations on a background
|
|
// SequencedTaskRunner.
|
|
class SSLKeyLoggerImpl::Core
|
|
: public base::RefCountedThreadSafe<SSLKeyLoggerImpl::Core> {
|
|
public:
|
|
Core() {
|
|
DETACH_FROM_SEQUENCE(sequence_checker_);
|
|
// That the user explicitly asked for debugging information would suggest
|
|
// waiting to flush these to disk, but some buggy antiviruses point this at
|
|
// a pipe and hang, so we avoid blocking shutdown. If writing to a real
|
|
// file, writes should complete quickly enough that this does not matter.
|
|
task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
|
|
{base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
|
|
}
|
|
|
|
Core(const Core&) = delete;
|
|
Core& operator=(const Core&) = delete;
|
|
|
|
void SetFile(base::File file) {
|
|
file_.reset(base::FileToFILE(std::move(file), "a"));
|
|
if (!file_)
|
|
DVLOG(1) << "Could not adopt file";
|
|
}
|
|
|
|
void OpenFile(const base::FilePath& path) {
|
|
task_runner_->PostTask(FROM_HERE,
|
|
base::BindOnce(&Core::OpenFileImpl, this, path));
|
|
}
|
|
|
|
void WriteLine(const std::string& line) {
|
|
bool was_empty;
|
|
{
|
|
base::AutoLock lock(lock_);
|
|
was_empty = buffer_.empty();
|
|
if (buffer_.size() < kMaxOutstandingLines) {
|
|
buffer_.push_back(line);
|
|
} else {
|
|
lines_dropped_ = true;
|
|
}
|
|
}
|
|
if (was_empty) {
|
|
task_runner_->PostTask(FROM_HERE, base::BindOnce(&Core::Flush, this));
|
|
}
|
|
}
|
|
|
|
private:
|
|
friend class base::RefCountedThreadSafe<Core>;
|
|
~Core() = default;
|
|
|
|
void OpenFileImpl(const base::FilePath& path) {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
DCHECK(!file_);
|
|
file_.reset(base::OpenFile(path, "a"));
|
|
if (!file_)
|
|
DVLOG(1) << "Could not open " << path.value();
|
|
}
|
|
|
|
void Flush() {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
|
bool lines_dropped = false;
|
|
std::vector<std::string> buffer;
|
|
{
|
|
base::AutoLock lock(lock_);
|
|
std::swap(lines_dropped, lines_dropped_);
|
|
std::swap(buffer, buffer_);
|
|
}
|
|
|
|
if (file_) {
|
|
for (const auto& line : buffer) {
|
|
fprintf(file_.get(), "%s\n", line.c_str());
|
|
}
|
|
if (lines_dropped) {
|
|
fprintf(file_.get(), "# Some lines were dropped due to slow writes.\n");
|
|
}
|
|
fflush(file_.get());
|
|
}
|
|
}
|
|
|
|
scoped_refptr<base::SequencedTaskRunner> task_runner_;
|
|
base::ScopedFILE file_;
|
|
SEQUENCE_CHECKER(sequence_checker_);
|
|
|
|
base::Lock lock_;
|
|
bool lines_dropped_ GUARDED_BY(lock_) = false;
|
|
std::vector<std::string> buffer_ GUARDED_BY(lock_);
|
|
};
|
|
|
|
SSLKeyLoggerImpl::SSLKeyLoggerImpl(const base::FilePath& path)
|
|
: core_(base::MakeRefCounted<Core>()) {
|
|
core_->OpenFile(path);
|
|
}
|
|
|
|
SSLKeyLoggerImpl::SSLKeyLoggerImpl(base::File file)
|
|
: core_(base::MakeRefCounted<Core>()) {
|
|
core_->SetFile(std::move(file));
|
|
}
|
|
|
|
SSLKeyLoggerImpl::~SSLKeyLoggerImpl() = default;
|
|
|
|
void SSLKeyLoggerImpl::WriteLine(const std::string& line) {
|
|
core_->WriteLine(line);
|
|
}
|
|
|
|
} // namespace net
|