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 {
59 mReplyMessage = s;
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 {
67 mReplyVersion = s;
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
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