blob: 1ab38358c6fd54eb31f59d33eb292d466e227468 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/headless/test/capture_std_stream.h"
#include <fcntl.h>
#include <stdio.h>
#include "base/check_op.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_WIN)
#include <io.h>
#else
#include <unistd.h>
#endif
namespace headless {
namespace {
enum { kReadPipe, kWritePipe };
static constexpr char kPipeEnd = '\xff';
} // namespace
CaptureStdStream::CaptureStdStream(FILE* stream) : stream_(stream) {
#if BUILDFLAG(IS_WIN)
CHECK_EQ(_pipe(pipes_.data(), 4096, O_BINARY), 0);
#else
CHECK_EQ(pipe(pipes_.data()), 0);
#endif
fileno_ = dup(fileno(stream_));
CHECK_NE(fileno_, -1);
}
CaptureStdStream::~CaptureStdStream() {
StopCapture();
close(pipes_[kReadPipe]);
close(pipes_[kWritePipe]);
close(fileno_);
}
void CaptureStdStream::StartCapture() {
if (capturing_) {
return;
}
fflush(stream_);
CHECK_NE(dup2(pipes_[kWritePipe], fileno(stream_)), -1);
capturing_ = true;
}
void CaptureStdStream::StopCapture() {
if (!capturing_) {
return;
}
char eop = kPipeEnd;
CHECK_NE(write(pipes_[kWritePipe], &eop, sizeof(eop)), -1);
fflush(stream_);
CHECK_NE(dup2(fileno_, fileno(stream_)), -1);
capturing_ = false;
}
std::string CaptureStdStream::TakeCapturedData() {
CHECK(!capturing_);
std::string captured_data;
for (;;) {
constexpr size_t kChunkSize = 256;
std::array<char, kChunkSize> buffer;
int bytes_read = read(pipes_[kReadPipe], buffer.data(), kChunkSize);
CHECK_GT(bytes_read, 0);
std::string_view data(buffer.data(), bytes_read);
if (data.back() != kPipeEnd) {
captured_data.append(data);
} else {
data.remove_suffix(1);
captured_data.append(data);
break;
}
}
return captured_data;
}
} // namespace headless