Project
Loading...
Searching...
No Matches
test_HTTPParser.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#include "../src/HTTPParser.h"
13#include <catch_amalgamated.hpp>
14
15using namespace o2::framework;
16
17class DPLParser : public HTTPParser
18{
19 public:
20 std::string mMethod;
21 std::string mPath;
22 std::string mVersion;
23 std::string mBody;
24 std::map<std::string, std::string> mHeaders;
25 void method(std::string_view const& m) override
26 {
27 mMethod = m;
28 }
29 void target(std::string_view const& p) override
30 {
31 mPath = p;
32 }
33
34 void version(std::string_view const& v) override
35 {
36 mVersion = v;
37 }
38 void header(std::string_view const& k, std::string_view const& v) override
39 {
40 mHeaders[std::string(k)] = v;
41 }
42 void body(char* buf, size_t s) override
43 {
44 mBody = buf;
45 }
46};
47
49{
50 public:
51 std::string mReplyVersion;
52 std::string mReplyCode;
53 std::string mReplyMessage;
54 std::string mBody;
55 std::map<std::string, std::string> mHeaders;
56
57 void replyMessage(std::string_view const& s) override
58 {
60 }
61 void replyCode(std::string_view const& s) override
62 {
63 mReplyCode = s;
64 }
65 void replyVersion(std::string_view const& s) override
66 {
68 }
69
70 void header(std::string_view const& k, std::string_view const& v) override
71 {
72 mHeaders[std::string(k)] = v;
73 }
74 void body(char* buf, size_t s) override
75 {
76 mBody = buf;
77 }
78};
79
81{
82 public:
83 std::vector<char const*> mFrame;
84 std::vector<size_t> mSize;
85 void frame(const char* f, size_t s) final
86 {
87 mFrame.push_back(strdup(f));
88 mSize.push_back(s);
89 }
90};
91
92TEST_CASE("HTTPParser1")
93{
94 {
95 char* request = strdup(
96 "GET / HTTP/1.1\r\n"
97 "x-dpl-pid: 124679842\r\n\r\nCONTROL QUIT");
98 DPLParser parser;
99 parse_http_request(request, strlen(request), &parser);
100 REQUIRE(std::string(parser.mMethod) == std::string("GET"));
101 REQUIRE(std::string(parser.mPath) == std::string("/"));
102 REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1"));
103 REQUIRE(parser.mHeaders.size() == 1);
104 }
105 {
106 char* request = strdup(
107 "GET / HTTP/1.1\r\n"
108 "x-dpl-pid: 124679842\r\n"
109 "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT");
110 DPLParser parser;
111 parse_http_request(request, strlen(request), &parser);
112 REQUIRE(std::string(parser.mMethod) == std::string("GET"));
113 REQUIRE(std::string(parser.mPath) == std::string("/"));
114 REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1"));
115 REQUIRE(parser.mHeaders.size() == 2);
116 REQUIRE(parser.mHeaders["x-dpl-pid"] == "124679842");
117 REQUIRE(parser.mHeaders["Somethingelse"] == "cjnjsdnjks");
118 REQUIRE(parser.mBody == "CONTROL QUIT");
119 }
120 {
121 // handle continuations...
122 char* request = strdup(
123 "GET / HTTP/1.1\r\n"
124 "x-dpl-pid: 124679842\r\n"
125 "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT");
126 char* request2 = strdup("FOO BAR");
127 DPLParser parser;
128 parse_http_request(request, strlen(request), &parser);
129 REQUIRE(std::string(parser.mMethod) == std::string("GET"));
130 REQUIRE(std::string(parser.mPath) == std::string("/"));
131 REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1"));
132 REQUIRE(parser.mHeaders.size() == 2);
133 REQUIRE(parser.mHeaders["x-dpl-pid"] == "124679842");
134 REQUIRE(parser.mHeaders["Somethingelse"] == "cjnjsdnjks");
135 REQUIRE(parser.mBody == "CONTROL QUIT");
136 parse_http_request(request2, strlen(request2), &parser);
137 REQUIRE(parser.mBody == "FOO BAR");
138 }
139
140 {
141 // WebSocket example
142 char* request = strdup(
143 "GET /chat HTTP/1.1\r\n"
144 "Host: server.example.com\r\n"
145 "Upgrade: websocket\r\n"
146 "Connection: Upgrade\r\n"
147 "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n"
148 "Sec-WebSocket-Protocol: chat, superchat\r\n"
149 "Sec-WebSocket-Version: 13\r\n"
150 "Origin: http://example.com\r\n\r\n");
151
152 DPLParser parser;
153 parse_http_request(request, strlen(request), &parser);
154 REQUIRE(std::string(parser.mMethod) == std::string("GET"));
155 REQUIRE(std::string(parser.mPath) == std::string("/chat"));
156 REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1"));
157 REQUIRE(parser.mHeaders.size() == 7);
158 REQUIRE(parser.mHeaders["Sec-WebSocket-Protocol"] == "chat, superchat");
159 }
160 {
161 // WebSocket example
162 char* request = strdup(
163 "HTTP/1.1 101 Switching Protocols\r\n"
164 "Upgrade: websocket\r\n"
165 "Connection: Upgrade\r\n"
166 "Access-Control-Allow-Origin: \"*\"\r\n"
167 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n");
168
169 DPLClientParser parser;
170 parser.states.push_back(HTTPState::IN_START_REPLY);
171 parse_http_request(request, strlen(request), &parser);
172 REQUIRE(std::string(parser.mReplyCode) == std::string("101"));
173 REQUIRE(std::string(parser.mReplyMessage) == std::string("Switching Protocols"));
174 REQUIRE(std::string(parser.mReplyVersion) == std::string("HTTP/1.1"));
175 REQUIRE(parser.mHeaders.size() == 4);
176 REQUIRE(parser.mHeaders["Sec-WebSocket-Accept"] == "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
177 REQUIRE(parser.mBody == "");
178 }
179 {
180 // WebSocket frame encoding / decoding
181 char* buffer = strdup("hello websockets!");
182 std::vector<uv_buf_t> encoded;
183 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
184 REQUIRE(encoded.size() == 1);
185 TestWSHandler handler;
186 REQUIRE(encoded[0].len == strlen(buffer) + 1 + 2);
187 ; // 1 for the 0, 2 for the header
188 decode_websocket(encoded[0].base, encoded[0].len, handler);
189 REQUIRE(handler.mSize[0] == strlen(buffer) + 1);
190 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
191 }
192 {
193 // WebSocket multiple frame encoding / decoding
194 char* buffer = strdup("hello websockets!");
195 std::vector<uv_buf_t> encoded;
196 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
197 REQUIRE(encoded.size() == 1);
198 char const* prototype = "and again.";
199 char* buffer2 = (char*)malloc(0x20000);
200 // fill the buffer with the prototype
201 size_t mod = strlen(prototype);
202 for (size_t i = 0; i < 0x20000; i++) {
203 buffer2[i] = prototype[i % mod];
204 }
205 buffer2[0x20000 - 1] = '\0';
206 encode_websocket_frames(encoded, buffer2, 0x20000, WebSocketOpCode::Binary, 0);
207 REQUIRE(encoded.size() == 2);
208 REQUIRE(encoded[1].len == 0x20000 + 10);
209 char* multiBuffer = (char*)malloc(encoded[0].len + encoded[1].len);
210 memcpy(multiBuffer, encoded[0].base, encoded[0].len);
211 memcpy(multiBuffer + encoded[0].len, encoded[1].base, encoded[1].len);
212
213 TestWSHandler handler;
214 decode_websocket(multiBuffer, encoded[0].len + encoded[1].len, handler);
215 REQUIRE(handler.mFrame.size() == 2);
216 REQUIRE(handler.mSize.size() == 2);
217 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
218 REQUIRE(std::string(handler.mFrame[1], handler.mSize[1] - 1) == std::string(buffer2));
219 }
220 {
221 // Decode a frame which is split in two.
222 char* buffer = strdup("hello websockets!1");
223 std::vector<uv_buf_t> encoded;
224 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
225 REQUIRE(encoded.size() == 1);
226
227 TestWSHandler handler;
228 decode_websocket(encoded[0].base, encoded[0].len / 2, handler);
229 decode_websocket(encoded[0].base + encoded[0].len / 2, encoded[0].len - encoded[0].len / 2, handler);
230 REQUIRE(handler.mFrame.size() == 1);
231 REQUIRE(handler.mSize.size() == 1);
232 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
233 }
234 {
235 // Decode a long frame which is split in two.
236 char* buffer = strdup("string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad");
237 std::vector<uv_buf_t> encoded;
238 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
239 REQUIRE(encoded.size() == 1);
240
241 TestWSHandler handler;
242 decode_websocket(encoded[0].base, encoded[0].len / 2, handler);
243 decode_websocket(encoded[0].base + encoded[0].len / 2, encoded[0].len - encoded[0].len / 2, handler);
244 REQUIRE(handler.mFrame.size() == 1);
245 REQUIRE(handler.mSize.size() == 1);
246 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
247 }
248 {
249 // WebSocket multiple frame encoding / decoding, long frames
250 char* buffer = strdup("dwqnocewnclkanklcdanslkcndklsnclkdsnckldsnclk cnldcl dsklc dslk cljdnsck sdlakcn askc sdkla cnsd c sdcn dsklncn dklsc nsdkl cklds clkds ckls dklc shello websockets!");
251 std::vector<uv_buf_t> encoded;
252 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
253 REQUIRE(encoded.size() == 1);
254 char const* buffer2 = "xsanjkcnsadjknc dsjc nsdnc dlscndsck dsc ds clds cds vnlsfl nklnjk nj nju n nio nkmnklfmdkl mkld mkl mkl mkl mlk m lkm klfdnkln jkafdnk nk mkldfm lkdamlkdmlkdmlk m klml km lkm kl.";
255 encode_websocket_frames(encoded, buffer2, strlen(buffer2) + 1, WebSocketOpCode::Binary, 0);
256 REQUIRE(encoded.size() == 1);
257
258 TestWSHandler handler;
259 decode_websocket(encoded[0].base, encoded[0].len, handler);
260 REQUIRE(handler.mFrame.size() == 2);
261 REQUIRE(handler.mSize.size() == 2);
262 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
263 REQUIRE(std::string(handler.mFrame[1], handler.mSize[1] - 1) == std::string(buffer2));
264 }
265 {
266 // Decode a long frame which is split in two, after the first byte.
267 char* buffer = strdup("string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad");
268 std::vector<uv_buf_t> encoded;
269 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
270 REQUIRE(encoded.size() == 1);
271
272 for (size_t i = 1; i < strlen(buffer); ++i) {
273 char buffer1[1024];
274 char buffer2[1024];
275 memset(buffer1, 0xfa, 1024);
276 memset(buffer2, 0xfb, 1024);
277 memcpy(buffer1, encoded[0].base, i);
278 memcpy(buffer2, encoded[0].base + i, encoded[0].len - i);
279 TestWSHandler handler;
280 decode_websocket(buffer1, i, handler);
281 decode_websocket(buffer2, encoded[0].len - i, handler);
282 REQUIRE(handler.mFrame.size() == 1);
283 REQUIRE(handler.mSize.size() == 1);
284 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
285 }
286 }
287 {
288 // Decode a long frame which is split in two, after the first byte.
289 char* buffer = strdup("string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad");
290 std::vector<uv_buf_t> encoded;
291 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
292 REQUIRE(encoded.size() == 1);
293
294 for (size_t i = 0; i < strlen(buffer) - 1; ++i) {
295 for (size_t j = i + 1; j < strlen(buffer); ++j) {
296 char buffer1[1024];
297 char buffer2[1024];
298 char buffer3[1024];
299 memset(buffer1, 0xfa, 1024);
300 memset(buffer2, 0xfb, 1024);
301 memset(buffer3, 0xfc, 1024);
302 memcpy(buffer1, encoded[0].base, i);
303 memcpy(buffer2, encoded[0].base + i, (j - i));
304 memcpy(buffer3, encoded[0].base + j, encoded[0].len - j);
305 TestWSHandler handler;
306 decode_websocket(buffer1, i, handler);
307 REQUIRE(handler.mFrame.size() == 0);
308 decode_websocket(buffer2, (j - i), handler);
309 REQUIRE(handler.mFrame.size() == 0);
310 decode_websocket(buffer3, encoded[0].len - j, handler);
311 REQUIRE(handler.mFrame.size() == 1);
312 REQUIRE(handler.mSize.size() == 1);
313 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
314 }
315 }
316 }
317 {
318 std::string checkRequest =
319 "GET /chat HTTP/1.1\r\n"
320 "Upgrade: websocket\r\n"
321 "Connection: Upgrade\r\n"
322 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
323 "Sec-WebSocket-Protocol: myprotocol\r\n"
324 "Sec-WebSocket-Version: 13\r\n\r\n";
325 std::string checkReply =
326 "HTTP/1.1 101 Switching Protocols\r\n"
327 "Upgrade: websocket\r\n"
328 "Connection: Upgrade\r\n"
329 "Access-Control-Allow-Origin: \"*\"\r\n"
330 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n";
331 int someSeed = 123;
332 std::string result = encode_websocket_handshake_request("/chat", "myprotocol", 13, "dGhlIHNhbXBsZSBub25jZQ==");
333 REQUIRE(result == checkRequest);
334
335 std::string reply = encode_websocket_handshake_reply("dGhlIHNhbXBsZSBub25jZQ==");
336 REQUIRE(reply == checkReply);
337 }
338}
339
340TEST_CASE("URLParser")
341{
342 {
343 auto [ip, port] = o2::framework::parse_websocket_url("ws://");
344 REQUIRE(ip == "127.0.0.1");
345 REQUIRE(port == 8080);
346 }
347 {
348 auto [ip, port] = o2::framework::parse_websocket_url("ws://127.0.0.1:8080");
349 REQUIRE(ip == "127.0.0.1");
350 REQUIRE(port == 8080);
351 }
352 {
353 auto [ip, port] = o2::framework::parse_websocket_url("ws://0.0.0.0:8080");
354 REQUIRE(ip == "0.0.0.0");
355 REQUIRE(port == 8080);
356 }
357 {
358 auto [ip, port] = o2::framework::parse_websocket_url("ws://0.0.0.0:8081");
359 REQUIRE(ip == "0.0.0.0");
360 REQUIRE(port == 8081);
361 }
362}
int32_t i
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
uint32_t j
Definition RawData.h:0
void replyMessage(std::string_view const &s) override
void header(std::string_view const &k, std::string_view const &v) override
std::string mReplyCode
std::string mReplyMessage
std::string mReplyVersion
std::map< std::string, std::string > mHeaders
void body(char *buf, size_t s) override
void replyCode(std::string_view const &s) override
void replyVersion(std::string_view const &s) override
void version(std::string_view const &v) override
void body(char *buf, size_t s) override
std::string mMethod
void header(std::string_view const &k, std::string_view const &v) override
std::string mBody
std::string mPath
void method(std::string_view const &m) override
std::string mVersion
void target(std::string_view const &p) override
std::map< std::string, std::string > mHeaders
std::vector< size_t > mSize
void frame(const char *f, size_t s) final
std::vector< char const * > mFrame
const GLfloat * m
Definition glcorearb.h:4066
GLuint64EXT * result
Definition glcorearb.h:5662
const GLdouble * v
Definition glcorearb.h:832
GLdouble f
Definition glcorearb.h:310
GLenum GLenum GLsizei len
Definition glcorearb.h:4232
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glcorearb.h:2514
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
TEST_CASE("test_prepareArguments")
void encode_websocket_frames(std::vector< uv_buf_t > &outputs, char const *src, size_t size, WebSocketOpCode opcode, uint32_t mask)
std::pair< std::string, unsigned short > parse_websocket_url(char const *url)
void parse_http_request(char *start, size_t size, HTTPParser *parser)
std::string encode_websocket_handshake_request(const char *endpoint, const char *protocol, int version, char const *nonce, std::vector< std::pair< std::string, std::string > > headers)
void decode_websocket(char *start, size_t size, WebSocketHandler &handler)
std::string encode_websocket_handshake_reply(char const *nonce, const char *protocol)
std::vector< HTTPState > states
Definition HTTPParser.h:219
An handler for a websocket message stream.
Definition HTTPParser.h:149
void * malloc(size_t n)