Bug 1893155 - Part 6: Correct constant for minimum epoch day. r=spidermonkey-reviewer...
[gecko.git] / third_party / content_analysis_sdk / demo / handler_misbehaving.h
blobbb0b4f18adcffeb1d529d3dce1119a3e4dfa1d7b
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef CONTENT_ANALYSIS_DEMO_HANDLER_MISBEHAVING_H_
6 #define CONTENT_ANALYSIS_DEMO_HANDLER_MISBEHAVING_H_
8 #include <time.h>
10 #include <algorithm>
11 #include <chrono>
12 #include <fstream>
13 #include <map>
14 #include <iostream>
15 #include <utility>
16 #include <vector>
17 #include <regex>
18 #include <windows.h>
20 #include "content_analysis/sdk/analysis.pb.h"
21 #include "content_analysis/sdk/analysis_agent.h"
22 #include "agent/src/event_win.h"
23 #include "handler.h"
25 enum class Mode {
26 // Have to use a "Mode_" prefix to avoid preprocessing problems in StringToMode
27 #define AGENT_MODE(name) Mode_##name,
28 #include "modes.h"
29 #undef AGENT_MODE
32 extern std::map<std::string, Mode> sStringToMode;
33 extern std::map<Mode, std::string> sModeToString;
35 // Writes a string to the pipe. Returns ERROR_SUCCESS if successful, else
36 // returns GetLastError() of the write. This function does not return until
37 // the entire message has been sent (or an error occurs).
38 static DWORD WriteBigMessageToPipe(HANDLE pipe, const std::string& message) {
39 std::cout << "[demo] WriteBigMessageToPipe top, message size is "
40 << message.size() << std::endl;
41 if (message.empty()) {
42 return ERROR_SUCCESS;
45 OVERLAPPED overlapped;
46 memset(&overlapped, 0, sizeof(overlapped));
47 overlapped.hEvent = CreateEvent(/*securityAttr=*/nullptr,
48 /*manualReset=*/TRUE,
49 /*initialState=*/FALSE,
50 /*name=*/nullptr);
51 if (overlapped.hEvent == nullptr) {
52 return GetLastError();
55 DWORD err = ERROR_SUCCESS;
56 const char* cursor = message.data();
57 for (DWORD size = message.length(); size > 0;) {
58 std::cout << "[demo] WriteBigMessageToPipe top of loop, remaining size "
59 << size << std::endl;
60 if (WriteFile(pipe, cursor, size, /*written=*/nullptr, &overlapped)) {
61 std::cout << "[demo] WriteBigMessageToPipe: success" << std::endl;
62 err = ERROR_SUCCESS;
63 break;
66 // If an I/O is not pending, return the error.
67 err = GetLastError();
68 if (err != ERROR_IO_PENDING) {
69 std::cout
70 << "[demo] WriteBigMessageToPipe: returning error from WriteFile "
71 << err << std::endl;
72 break;
75 DWORD written;
76 if (!GetOverlappedResult(pipe, &overlapped, &written, /*wait=*/TRUE)) {
77 err = GetLastError();
78 std::cout << "[demo] WriteBigMessageToPipe: returning error from "
79 "GetOverlappedREsult "
80 << err << std::endl;
81 break;
84 // reset err for the next loop iteration
85 err = ERROR_SUCCESS;
86 std::cout << "[demo] WriteBigMessageToPipe: bottom of loop, wrote "
87 << written << std::endl;
88 cursor += written;
89 size -= written;
92 CloseHandle(overlapped.hEvent);
93 return err;
96 // An AgentEventHandler that does various misbehaving things
97 class MisbehavingHandler final : public Handler {
98 public:
99 using Event = content_analysis::sdk::ContentAnalysisEvent;
101 static
102 std::unique_ptr<AgentEventHandler> Create(
103 const std::string& modeStr,
104 std::vector<unsigned long>&& delays,
105 const std::string& print_data_file_path,
106 RegexArray&& toBlock = RegexArray(),
107 RegexArray&& toWarn = RegexArray(),
108 RegexArray&& toReport = RegexArray()) {
109 auto it = sStringToMode.find(modeStr);
110 if (it == sStringToMode.end()) {
111 std::cout << "\"" << modeStr << "\""
112 << " is not a valid mode!" << std::endl;
113 return nullptr;
116 return std::unique_ptr<AgentEventHandler>(new MisbehavingHandler(it->second, std::move(delays), print_data_file_path, std::move(toBlock), std::move(toWarn), std::move(toReport)));
119 private:
120 MisbehavingHandler(Mode mode, std::vector<unsigned long>&& delays, const std::string& print_data_file_path,
121 RegexArray&& toBlock = RegexArray(),
122 RegexArray&& toWarn = RegexArray(),
123 RegexArray&& toReport = RegexArray()) :
124 Handler(std::move(delays), print_data_file_path, std::move(toBlock), std::move(toWarn), std::move(toReport)),
125 mode_(mode) {}
128 template <size_t N>
129 DWORD SendBytesOverPipe(const unsigned char (&bytes)[N],
130 const std::unique_ptr<Event>& event) {
131 content_analysis::sdk::ContentAnalysisEventWin* eventWin =
132 static_cast<content_analysis::sdk::ContentAnalysisEventWin*>(
133 event.get());
134 HANDLE pipe = eventWin->Pipe();
135 std::string s(reinterpret_cast<const char*>(bytes), N);
136 return WriteBigMessageToPipe(pipe, s);
139 bool SetCustomResponse(AtomicCout& aout, std::unique_ptr<Event>& event) override {
140 std::cout << std::endl << "----------" << std::endl << std::endl;
141 std::cout << "Mode is " << sModeToString[mode_] << std::endl;
143 bool handled = true;
144 if (mode_ == Mode::Mode_largeResponse) {
145 for (size_t i = 0; i < 1000; ++i) {
146 content_analysis::sdk::ContentAnalysisResponse_Result* result =
147 event->GetResponse().add_results();
148 result->set_tag("someTag");
149 content_analysis::sdk::ContentAnalysisResponse_Result_TriggeredRule*
150 triggeredRule = result->add_triggered_rules();
151 triggeredRule->set_rule_id("some_id");
152 triggeredRule->set_rule_name("some_name");
154 } else if (mode_ ==
155 Mode::Mode_invalidUtf8StringStartByteIsContinuationByte) {
156 // protobuf docs say
157 // "A string must always contain UTF-8 encoded text."
158 // So let's try something invalid
159 // Anything with bits 10xxxxxx is only a continuation code point
160 event->GetResponse().set_request_token("\x80\x41\x41\x41");
161 } else if (mode_ ==
162 Mode::Mode_invalidUtf8StringEndsInMiddleOfMultibyteSequence) {
163 // f0 byte indicates there should be 3 bytes following it, but here
164 // there are only 2
165 event->GetResponse().set_request_token("\x41\xf0\x90\x8d");
166 } else if (mode_ == Mode::Mode_invalidUtf8StringOverlongEncoding) {
167 // codepoint U+20AC, should be encoded in 3 bytes (E2 82 AC)
168 // instead of 4
169 event->GetResponse().set_request_token("\xf0\x82\x82\xac");
170 } else if (mode_ == Mode::Mode_invalidUtf8StringMultibyteSequenceTooShort) {
171 // f0 byte indicates there should be 3 bytes following it, but here
172 // there are only 2 (\x41 is not a continuation byte)
173 event->GetResponse().set_request_token("\xf0\x90\x8d\x41");
174 } else if (mode_ == Mode::Mode_invalidUtf8StringDecodesToInvalidCodePoint) {
175 // decodes to U+1FFFFF, but only up to U+10FFFF is a valid code point
176 event->GetResponse().set_request_token("\xf7\xbf\xbf\xbf");
177 } else if (mode_ == Mode::Mode_stringWithEmbeddedNull) {
178 event->GetResponse().set_request_token("\x41\x00\x41");
179 } else if (mode_ == Mode::Mode_zeroResults) {
180 event->GetResponse().clear_results();
181 } else if (mode_ == Mode::Mode_resultWithInvalidStatus) {
182 // This causes an assertion failure and the process exits
183 // So we just serialize this ourselves in SendCustomResponse()
184 /*content_analysis::sdk::ContentAnalysisResponse_Result* result =
185 event->GetResponse().mutable_results(0);
186 result->set_status(
187 static_cast<
188 ::content_analysis::sdk::ContentAnalysisResponse_Result_Status>(
189 100));*/
190 } else {
191 handled = false;
193 return handled;
196 bool SendCustomResponse(std::unique_ptr<Event>& event) override {
197 if (mode_ == Mode::Mode_largeResponse) {
198 content_analysis::sdk::ContentAnalysisEventWin* eventWin =
199 static_cast<content_analysis::sdk::ContentAnalysisEventWin*>(
200 event.get());
201 HANDLE pipe = eventWin->Pipe();
202 std::cout << "largeResponse about to write" << std::endl;
203 DWORD result = WriteBigMessageToPipe(
204 pipe, eventWin->SerializeStringToSendToBrowser());
205 std::cout << "largeResponse done writing with error " << result
206 << std::endl;
207 eventWin->SetResponseSent();
208 } else if (mode_ == Mode::Mode_resultWithInvalidStatus) {
209 content_analysis::sdk::ContentAnalysisEventWin* eventWin =
210 static_cast<content_analysis::sdk::ContentAnalysisEventWin*>(
211 event.get());
212 HANDLE pipe = eventWin->Pipe();
213 std::string serializedString = eventWin->SerializeStringToSendToBrowser();
214 // The last byte is the status value. Set it to 100
215 serializedString[serializedString.length() - 1] = 100;
216 WriteBigMessageToPipe(pipe, serializedString);
217 } else if (mode_ == Mode::Mode_messageTruncatedInMiddleOfString) {
218 unsigned char bytes[5];
219 bytes[0] = 10; // field 1 (request_token), LEN encoding
220 bytes[1] = 13; // length 13
221 bytes[2] = 65; // "A"
222 bytes[3] = 66; // "B"
223 bytes[4] = 67; // "C"
224 SendBytesOverPipe(bytes, event);
225 } else if (mode_ == Mode::Mode_messageWithInvalidWireType) {
226 unsigned char bytes[5];
227 bytes[0] = 15; // field 1 (request_token), "7" encoding (invalid value)
228 bytes[1] = 3; // length 3
229 bytes[2] = 65; // "A"
230 bytes[3] = 66; // "B"
231 bytes[4] = 67; // "C"
232 SendBytesOverPipe(bytes, event);
233 } else if (mode_ == Mode::Mode_messageWithUnusedFieldNumber) {
234 unsigned char bytes[5];
235 bytes[0] = 82; // field 10 (this is invalid), LEN encoding
236 bytes[1] = 3; // length 3
237 bytes[2] = 65; // "A"
238 bytes[3] = 66; // "B"
239 bytes[4] = 67; // "C"
240 SendBytesOverPipe(bytes, event);
241 } else if (mode_ == Mode::Mode_messageWithWrongStringWireType) {
242 unsigned char bytes[2];
243 bytes[0] = 10; // field 1 (request_token), VARINT encoding (but should be
244 // a string/LEN)
245 bytes[1] = 42; // value 42
246 SendBytesOverPipe(bytes, event);
247 } else if (mode_ == Mode::Mode_messageWithZeroTag) {
248 unsigned char bytes[1];
249 // The protobuf deserialization code seems to handle this
250 // in a special case.
251 bytes[0] = 0;
252 SendBytesOverPipe(bytes, event);
253 } else if (mode_ == Mode::Mode_messageWithZeroFieldButNonzeroWireType) {
254 // The protobuf deserialization code seems to handle this
255 // in a special case.
256 unsigned char bytes[5];
257 bytes[0] = 2; // field 0 (invalid), LEN encoding
258 bytes[1] = 3; // length 13
259 bytes[2] = 65; // "A"
260 bytes[3] = 66; // "B"
261 bytes[4] = 67; // "C"
262 SendBytesOverPipe(bytes, event);
263 } else if (mode_ == Mode::Mode_messageWithGroupEnd) {
264 // GROUP_ENDs are obsolete and the deserialization code
265 // handles them in a special case.
266 unsigned char bytes[1];
267 bytes[0] = 12; // field 1 (request_token), GROUP_END encoding
268 SendBytesOverPipe(bytes, event);
269 } else if (mode_ == Mode::Mode_messageTruncatedInMiddleOfVarint) {
270 unsigned char bytes[2];
271 bytes[0] = 16; // field 2 (status), VARINT encoding
272 bytes[1] = 128; // high bit is set, indicating there
273 // should be a byte after this
274 SendBytesOverPipe(bytes, event);
275 } else if (mode_ == Mode::Mode_messageTruncatedInMiddleOfTag) {
276 unsigned char bytes[1];
277 bytes[0] = 128; // tag is actually encoded as a VARINT, so set the high
278 // bit, indicating there should be a byte after this
279 SendBytesOverPipe(bytes, event);
280 } else {
281 return false;
283 return true;
286 private:
287 Mode mode_;
290 #endif // CONTENT_ANALYSIS_DEMO_HANDLER_MISBEHAVING_H_