diff options
Diffstat (limited to 'third_party/content_analysis_sdk/agent/src/event_win.cc')
-rw-r--r-- | third_party/content_analysis_sdk/agent/src/event_win.cc | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/third_party/content_analysis_sdk/agent/src/event_win.cc b/third_party/content_analysis_sdk/agent/src/event_win.cc new file mode 100644 index 0000000000..907bdfb858 --- /dev/null +++ b/third_party/content_analysis_sdk/agent/src/event_win.cc @@ -0,0 +1,133 @@ +// 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 <ios> +#include <iostream> +#include <sstream> +#include <utility> + +#include "event_win.h" + +#include "common/utils_win.h" + +#include "agent_utils_win.h" +#include "scoped_print_handle_win.h" + +namespace content_analysis { +namespace sdk { + +// Writes a string to the pipe. Returns ERROR_SUCCESS if successful, else +// returns GetLastError() of the write. This function does not return until +// the entire message has been sent (or an error occurs). +static DWORD WriteMessageToPipe(HANDLE pipe, const std::string& message) { + if (message.empty()) { + return ERROR_SUCCESS; + } + + internal::ScopedOverlapped overlapped; + if (!overlapped.is_valid()) { + return GetLastError(); + } + + DWORD err = ERROR_SUCCESS; + const char* cursor = message.data(); + for (DWORD size = message.length(); size > 0;) { + if (WriteFile(pipe, cursor, size, /*written=*/nullptr, overlapped)) { + err = ERROR_SUCCESS; + break; + } + + // If an I/O is not pending, return the error. + err = GetLastError(); + if (err != ERROR_IO_PENDING) { + break; + } + + DWORD written; + if (!GetOverlappedResult(pipe, overlapped, &written, /*wait=*/TRUE)) { + err = GetLastError(); + break; + } + + cursor += written; + size -= written; + } + + return err; +} + + +ContentAnalysisEventWin::ContentAnalysisEventWin( + HANDLE handle, + const BrowserInfo& browser_info, + ContentAnalysisRequest req) + : ContentAnalysisEventBase(browser_info), + hPipe_(handle) { + *request() = std::move(req); +} + +ContentAnalysisEventWin::~ContentAnalysisEventWin() { + Shutdown(); +} + +ResultCode ContentAnalysisEventWin::Init() { + // TODO(rogerta): do some extra validation of the request? + if (request()->request_token().empty()) { + return ResultCode::ERR_MISSING_REQUEST_TOKEN; + } + + response()->set_request_token(request()->request_token()); + + // Prepare the response so that ALLOW verdicts are the default(). + return UpdateResponse(*response(), + request()->tags_size() > 0 ? request()->tags(0) : std::string(), + ContentAnalysisResponse::Result::SUCCESS); +} + +ResultCode ContentAnalysisEventWin::Close() { + Shutdown(); + return ContentAnalysisEventBase::Close(); +} + +ResultCode ContentAnalysisEventWin::Send() { + if (response_sent_) { + return ResultCode::ERR_RESPONSE_ALREADY_SENT; + } + + response_sent_ = true; + + DWORD err = WriteMessageToPipe(hPipe_, + agent_to_chrome()->SerializeAsString()); + return ErrorToResultCode(err); +} + +std::string ContentAnalysisEventWin::DebugString() const { + std::stringstream state; + state.setf(std::ios::boolalpha); + state << "ContentAnalysisEventWin{handle=" << hPipe_; + state << " pid=" << GetBrowserInfo().pid; + state << " rtoken=" << GetRequest().request_token(); + state << " sent=" << response_sent_; + state << "}" << std::ends; + + return state.str(); +} + +void ContentAnalysisEventWin::Shutdown() { + if (hPipe_ != INVALID_HANDLE_VALUE) { + // If no response has been sent yet, attempt to send it now. Otherwise + // the client may be stuck waiting. After shutdown the agent will not + // have any other chance to respond. + if (!response_sent_) { + Send(); + } + + // This event does not own the pipe, so don't close it. + FlushFileBuffers(hPipe_); + hPipe_ = INVALID_HANDLE_VALUE; + } +} + +} // namespace sdk +} // namespace content_analysis |