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 <boost/test/tools/old/interface.hpp>
13
14#include "../src/HTTPParser.h"
15#include <catch_amalgamated.hpp>
16
17using namespace o2::framework;
18
19class DPLParser : public HTTPParser
20{
21 public:
22 std::string mMethod;
23 std::string mPath;
24 std::string mVersion;
25 std::string mBody;
26 std::map<std::string, std::string> mHeaders;
27 void method(std::string_view const& m) override
28 {
29 mMethod = m;
30 }
31 void target(std::string_view const& p) override
32 {
33 mPath = p;
34 }
35
36 void version(std::string_view const& v) override
37 {
38 mVersion = v;
39 }
40 void header(std::string_view const& k, std::string_view const& v) override
41 {
42 mHeaders[std::string(k)] = v;
43 }
44 void body(char* buf, size_t s) override
45 {
46 mBody = buf;
47 }
48};
49
51{
52 public:
53 std::string mReplyVersion;
54 std::string mReplyCode;
55 std::string mReplyMessage;
56 std::string mBody;
57 std::map<std::string, std::string> mHeaders;
58
59 void replyMessage(std::string_view const& s) override
60 {
61 mReplyMessage = s;
62 }
63 void replyCode(std::string_view const& s) override
64 {
65 mReplyCode = s;
66 }
67 void replyVersion(std::string_view const& s) override
68 {
69 mReplyVersion = s;
70 }
71
72 void header(std::string_view const& k, std::string_view const& v) override
73 {
74 mHeaders[std::string(k)] = v;
75 }
76 void body(char* buf, size_t s) override
77 {
78 mBody = buf;
79 }
80};
81
83{
84 public:
85 std::vector<char const*> mFrame;
86 std::vector<size_t> mSize;
87 void frame(const char* f, size_t s) final
88 {
89 mFrame.push_back(strdup(f));
90 mSize.push_back(s);
91 }
92};
93
94TEST_CASE("HTTPParser1")
95{
96 {
97 char* request = strdup(
98 "GET / HTTP/1.1\r\n"
99 "x-dpl-pid: 124679842\r\n\r\nCONTROL QUIT");
100 DPLParser parser;
101 parse_http_request(request, strlen(request), &parser);
102 REQUIRE(std::string(parser.mMethod) == std::string("GET"));
103 REQUIRE(std::string(parser.mPath) == std::string("/"));
104 REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1"));
105 REQUIRE(parser.mHeaders.size() == 1);
106 }
107 {
108 char* request = strdup(
109 "GET / HTTP/1.1\r\n"
110 "x-dpl-pid: 124679842\r\n"
111 "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT");
112 DPLParser parser;
113 parse_http_request(request, strlen(request), &parser);
114 REQUIRE(std::string(parser.mMethod) == std::string("GET"));
115 REQUIRE(std::string(parser.mPath) == std::string("/"));
116 REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1"));
117 REQUIRE(parser.mHeaders.size() == 2);
118 REQUIRE(parser.mHeaders["x-dpl-pid"] == "124679842");
119 REQUIRE(parser.mHeaders["Somethingelse"] == "cjnjsdnjks");
120 REQUIRE(parser.mBody == "CONTROL QUIT");
121 }
122 {
123 // handle continuations...
124 char* request = strdup(
125 "GET / HTTP/1.1\r\n"
126 "x-dpl-pid: 124679842\r\n"
127 "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT");
128 char* request2 = strdup("FOO BAR");
129 DPLParser parser;
130 parse_http_request(request, strlen(request), &parser);
131 REQUIRE(std::string(parser.mMethod) == std::string("GET"));
132 REQUIRE(std::string(parser.mPath) == std::string("/"));
133 REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1"));
134 REQUIRE(parser.mHeaders.size() == 2);
135 REQUIRE(parser.mHeaders["x-dpl-pid"] == "124679842");
136 REQUIRE(parser.mHeaders["Somethingelse"] == "cjnjsdnjks");
137 REQUIRE(parser.mBody == "CONTROL QUIT");
138 parse_http_request(request2, strlen(request2), &parser);
139 REQUIRE(parser.mBody == "FOO BAR");
140 }
141
142 {
143 // WebSocket example
144 char* request = strdup(
145 "GET /chat HTTP/1.1\r\n"
146 "Host: server.example.com\r\n"
147 "Upgrade: websocket\r\n"
148 "Connection: Upgrade\r\n"
149 "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n"
150 "Sec-WebSocket-Protocol: chat, superchat\r\n"
151 "Sec-WebSocket-Version: 13\r\n"
152 "Origin: http://example.com\r\n\r\n");
153
154 DPLParser parser;
155 parse_http_request(request, strlen(request), &parser);
156 REQUIRE(std::string(parser.mMethod) == std::string("GET"));
157 REQUIRE(std::string(parser.mPath) == std::string("/chat"));
158 REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1"));
159 REQUIRE(parser.mHeaders.size() == 7);
160 REQUIRE(parser.mHeaders["Sec-WebSocket-Protocol"] == "chat, superchat");
161 }
162 {
163 // WebSocket example
164 char* request = strdup(
165 "HTTP/1.1 101 Switching Protocols\r\n"
166 "Upgrade: websocket\r\n"
167 "Connection: Upgrade\r\n"
168 "Access-Control-Allow-Origin: \"*\"\r\n"
169 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n");
170
171 DPLClientParser parser;
172 parser.states.push_back(HTTPState::IN_START_REPLY);
173 parse_http_request(request, strlen(request), &parser);
174 REQUIRE(std::string(parser.mReplyCode) == std::string("101"));
175 REQUIRE(std::string(parser.mReplyMessage) == std::string("Switching Protocols"));
176 REQUIRE(std::string(parser.mReplyVersion) == std::string("HTTP/1.1"));
177 REQUIRE(parser.mHeaders.size() == 4);
178 REQUIRE(parser.mHeaders["Sec-WebSocket-Accept"] == "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
179 REQUIRE(parser.mBody == "");
180 }
181 {
182 // WebSocket frame encoding / decoding
183 char* buffer = strdup("hello websockets!");
184 std::vector<uv_buf_t> encoded;
185 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
186 REQUIRE(encoded.size() == 1);
187 TestWSHandler handler;
188 REQUIRE(encoded[0].len == strlen(buffer) + 1 + 2);
189 ; // 1 for the 0, 2 for the header
190 decode_websocket(encoded[0].base, encoded[0].len, handler);
191 REQUIRE(handler.mSize[0] == strlen(buffer) + 1);
192 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
193 }
194 {
195 // WebSocket multiple frame encoding / decoding
196 char* buffer = strdup("hello websockets!");
197 std::vector<uv_buf_t> encoded;
198 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
199 REQUIRE(encoded.size() == 1);
200 char const* prototype = "and again.";
201 char* buffer2 = (char*)malloc(0x20000);
202 // fill the buffer with the prototype
203 size_t mod = strlen(prototype);
204 for (size_t i = 0; i < 0x20000; i++) {
205 buffer2[i] = prototype[i % mod];
206 }
207 buffer2[0x20000 - 1] = '\0';
208 encode_websocket_frames(encoded, buffer2, 0x20000, WebSocketOpCode::Binary, 0);
209 REQUIRE(encoded.size() == 2);
210 REQUIRE(encoded[1].len == 0x20000 + 10);
211 char* multiBuffer = (char*)malloc(encoded[0].len + encoded[1].len);
212 memcpy(multiBuffer, encoded[0].base, encoded[0].len);
213 memcpy(multiBuffer + encoded[0].len, encoded[1].base, encoded[1].len);
214
215 TestWSHandler handler;
216 decode_websocket(multiBuffer, encoded[0].len + encoded[1].len, handler);
217 REQUIRE(handler.mFrame.size() == 2);
218 REQUIRE(handler.mSize.size() == 2);
219 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
220 REQUIRE(std::string(handler.mFrame[1], handler.mSize[1] - 1) == std::string(buffer2));
221 }
222 {
223 // Decode a frame which is split in two.
224 char* buffer = strdup("hello websockets!1");
225 std::vector<uv_buf_t> encoded;
226 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
227 REQUIRE(encoded.size() == 1);
228
229 TestWSHandler handler;
230 decode_websocket(encoded[0].base, encoded[0].len / 2, handler);
231 decode_websocket(encoded[0].base + encoded[0].len / 2, encoded[0].len - encoded[0].len / 2, handler);
232 REQUIRE(handler.mFrame.size() == 1);
233 REQUIRE(handler.mSize.size() == 1);
234 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
235 }
236 {
237 // Decode a long frame which is split in two.
238 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");
239 std::vector<uv_buf_t> encoded;
240 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
241 REQUIRE(encoded.size() == 1);
242
243 TestWSHandler handler;
244 decode_websocket(encoded[0].base, encoded[0].len / 2, handler);
245 decode_websocket(encoded[0].base + encoded[0].len / 2, encoded[0].len - encoded[0].len / 2, handler);
246 REQUIRE(handler.mFrame.size() == 1);
247 REQUIRE(handler.mSize.size() == 1);
248 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
249 }
250 {
251 // WebSocket multiple frame encoding / decoding, long frames
252 char* buffer = strdup("dwqnocewnclkanklcdanslkcndklsnclkdsnckldsnclk cnldcl dsklc dslk cljdnsck sdlakcn askc sdkla cnsd c sdcn dsklncn dklsc nsdkl cklds clkds ckls dklc shello websockets!");
253 std::vector<uv_buf_t> encoded;
254 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
255 REQUIRE(encoded.size() == 1);
256 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.";
257 encode_websocket_frames(encoded, buffer2, strlen(buffer2) + 1, WebSocketOpCode::Binary, 0);
258 REQUIRE(encoded.size() == 1);
259
260 TestWSHandler handler;
261 decode_websocket(encoded[0].base, encoded[0].len, handler);
262 REQUIRE(handler.mFrame.size() == 2);
263 REQUIRE(handler.mSize.size() == 2);
264 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
265 REQUIRE(std::string(handler.mFrame[1], handler.mSize[1] - 1) == std::string(buffer2));
266 }
267 {
268 // Decode a long frame which is split in two, after the first byte.
269 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");
270 std::vector<uv_buf_t> encoded;
271 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
272 REQUIRE(encoded.size() == 1);
273
274 for (size_t i = 1; i < strlen(buffer); ++i) {
275 char buffer1[1024];
276 char buffer2[1024];
277 memset(buffer1, 0xfa, 1024);
278 memset(buffer2, 0xfb, 1024);
279 memcpy(buffer1, encoded[0].base, i);
280 memcpy(buffer2, encoded[0].base + i, encoded[0].len - i);
281 TestWSHandler handler;
282 decode_websocket(buffer1, i, handler);
283 decode_websocket(buffer2, encoded[0].len - i, handler);
284 REQUIRE(handler.mFrame.size() == 1);
285 REQUIRE(handler.mSize.size() == 1);
286 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
287 }
288 }
289 {
290 // Decode a long frame which is split in two, after the first byte.
291 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");
292 std::vector<uv_buf_t> encoded;
293 encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0);
294 REQUIRE(encoded.size() == 1);
295
296 for (size_t i = 0; i < strlen(buffer) - 1; ++i) {
297 for (size_t j = i + 1; j < strlen(buffer); ++j) {
298 char buffer1[1024];
299 char buffer2[1024];
300 char buffer3[1024];
301 memset(buffer1, 0xfa, 1024);
302 memset(buffer2, 0xfb, 1024);
303 memset(buffer3, 0xfc, 1024);
304 memcpy(buffer1, encoded[0].base, i);
305 memcpy(buffer2, encoded[0].base + i, (j - i));
306 memcpy(buffer3, encoded[0].base + j, encoded[0].len - j);
307 TestWSHandler handler;
308 decode_websocket(buffer1, i, handler);
309 REQUIRE(handler.mFrame.size() == 0);
310 decode_websocket(buffer2, (j - i), handler);
311 REQUIRE(handler.mFrame.size() == 0);
312 decode_websocket(buffer3, encoded[0].len - j, handler);
313 REQUIRE(handler.mFrame.size() == 1);
314 REQUIRE(handler.mSize.size() == 1);
315 REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer));
316 }
317 }
318 }
319 {
320 std::string checkRequest =
321 "GET /chat HTTP/1.1\r\n"
322 "Upgrade: websocket\r\n"
323 "Connection: Upgrade\r\n"
324 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
325 "Sec-WebSocket-Protocol: myprotocol\r\n"
326 "Sec-WebSocket-Version: 13\r\n\r\n";
327 std::string checkReply =
328 "HTTP/1.1 101 Switching Protocols\r\n"
329 "Upgrade: websocket\r\n"
330 "Connection: Upgrade\r\n"
331 "Access-Control-Allow-Origin: \"*\"\r\n"
332 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n";
333 int someSeed = 123;
334 std::string result = encode_websocket_handshake_request("/chat", "myprotocol", 13, "dGhlIHNhbXBsZSBub25jZQ==");
335 REQUIRE(result == checkRequest);
336
337 std::string reply = encode_websocket_handshake_reply("dGhlIHNhbXBsZSBub25jZQ==");
338 REQUIRE(reply == checkReply);
339 }
340}
341
342TEST_CASE("URLParser")
343{
344 {
345 auto [ip, port] = o2::framework::parse_websocket_url("ws://");
346 REQUIRE(ip == "127.0.0.1");
347 REQUIRE(port == 8080);
348 }
349 {
350 auto [ip, port] = o2::framework::parse_websocket_url("ws://127.0.0.1:8080");
351 REQUIRE(ip == "127.0.0.1");
352 REQUIRE(port == 8080);
353 }
354 {
355 auto [ip, port] = o2::framework::parse_websocket_url("ws://0.0.0.0:8080");
356 REQUIRE(ip == "0.0.0.0");
357 REQUIRE(port == 8080);
358 }
359 {
360 auto [ip, port] = o2::framework::parse_websocket_url("ws://0.0.0.0:8081");
361 REQUIRE(ip == "0.0.0.0");
362 REQUIRE(port == 8081);
363 }
364}
int32_t i
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
GLuint buffer
Definition glcorearb.h:655
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 PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
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)
std::string encode_websocket_handshake_reply(char const *nonce)
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::vector< HTTPState > states
Definition HTTPParser.h:206
An handler for a websocket message stream.
Definition HTTPParser.h:136