event_win.cc (3487B)
1 // Copyright 2022 The Chromium Authors. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <ios> 6 #include <sstream> 7 #include <utility> 8 9 #include "event_win.h" 10 11 #include "common/utils_win.h" 12 13 #include "agent_utils_win.h" 14 #include "scoped_print_handle_win.h" 15 16 namespace content_analysis { 17 namespace sdk { 18 19 // Writes a string to the pipe. Returns ERROR_SUCCESS if successful, else 20 // returns GetLastError() of the write. This function does not return until 21 // the entire message has been sent (or an error occurs). 22 static DWORD WriteMessageToPipe(HANDLE pipe, const std::string& message) { 23 if (message.empty()) { 24 return ERROR_SUCCESS; 25 } 26 27 internal::ScopedOverlapped overlapped; 28 if (!overlapped.is_valid()) { 29 return GetLastError(); 30 } 31 32 DWORD err = ERROR_SUCCESS; 33 const char* cursor = message.data(); 34 for (DWORD size = message.length(); size > 0;) { 35 if (WriteFile(pipe, cursor, size, /*written=*/nullptr, overlapped)) { 36 err = ERROR_SUCCESS; 37 break; 38 } 39 40 // If an I/O is not pending, return the error. 41 err = GetLastError(); 42 if (err != ERROR_IO_PENDING) { 43 break; 44 } 45 46 DWORD written; 47 if (!GetOverlappedResult(pipe, overlapped, &written, /*wait=*/TRUE)) { 48 err = GetLastError(); 49 break; 50 } 51 52 cursor += written; 53 size -= written; 54 } 55 56 return err; 57 } 58 59 60 ContentAnalysisEventWin::ContentAnalysisEventWin( 61 HANDLE handle, 62 const BrowserInfo& browser_info, 63 ContentAnalysisRequest req) 64 : ContentAnalysisEventBase(browser_info), 65 hPipe_(handle) { 66 *request() = std::move(req); 67 } 68 69 ContentAnalysisEventWin::~ContentAnalysisEventWin() { 70 Shutdown(); 71 } 72 73 ResultCode ContentAnalysisEventWin::Init() { 74 // TODO(rogerta): do some extra validation of the request? 75 if (request()->request_token().empty()) { 76 return ResultCode::ERR_MISSING_REQUEST_TOKEN; 77 } 78 79 response()->set_request_token(request()->request_token()); 80 81 // Prepare the response so that ALLOW verdicts are the default(). 82 return UpdateResponse(*response(), 83 request()->tags_size() > 0 ? request()->tags(0) : std::string(), 84 ContentAnalysisResponse::Result::SUCCESS); 85 } 86 87 ResultCode ContentAnalysisEventWin::Close() { 88 Shutdown(); 89 return ContentAnalysisEventBase::Close(); 90 } 91 92 ResultCode ContentAnalysisEventWin::Send() { 93 if (response_sent_) { 94 return ResultCode::ERR_RESPONSE_ALREADY_SENT; 95 } 96 97 response_sent_ = true; 98 99 DWORD err = WriteMessageToPipe(hPipe_, 100 agent_to_chrome()->SerializeAsString()); 101 return ErrorToResultCode(err); 102 } 103 104 std::string ContentAnalysisEventWin::DebugString() const { 105 std::stringstream state; 106 state.setf(std::ios::boolalpha); 107 state << "ContentAnalysisEventWin{handle=" << hPipe_; 108 state << " pid=" << GetBrowserInfo().pid; 109 state << " rtoken=" << GetRequest().request_token(); 110 state << " sent=" << response_sent_; 111 state << "}" << std::ends; 112 113 return state.str(); 114 } 115 116 void ContentAnalysisEventWin::Shutdown() { 117 if (hPipe_ != INVALID_HANDLE_VALUE) { 118 // If no response has been sent yet, attempt to send it now. Otherwise 119 // the client may be stuck waiting. After shutdown the agent will not 120 // have any other chance to respond. 121 if (!response_sent_) { 122 Send(); 123 } 124 125 // This event does not own the pipe, so don't close it. 126 FlushFileBuffers(hPipe_); 127 hPipe_ = INVALID_HANDLE_VALUE; 128 } 129 } 130 131 } // namespace sdk 132 } // namespace content_analysis