1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
// 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
|