1 | // |
2 | // WebSocketTest.cpp |
3 | // |
4 | // Copyright (c) 2012, Applied Informatics Software Engineering GmbH. |
5 | // and Contributors. |
6 | // |
7 | // SPDX-License-Identifier: BSL-1.0 |
8 | // |
9 | |
10 | |
11 | #include "WebSocketTest.h" |
12 | #include "Poco/CppUnit/TestCaller.h" |
13 | #include "Poco/CppUnit/TestSuite.h" |
14 | #include "Poco/Net/WebSocket.h" |
15 | #include "Poco/Net/SocketStream.h" |
16 | #include "Poco/Net/HTTPClientSession.h" |
17 | #include "Poco/Net/HTTPServer.h" |
18 | #include "Poco/Net/HTTPServerParams.h" |
19 | #include "Poco/Net/HTTPRequestHandler.h" |
20 | #include "Poco/Net/HTTPRequestHandlerFactory.h" |
21 | #include "Poco/Net/HTTPServerRequest.h" |
22 | #include "Poco/Net/HTTPServerResponse.h" |
23 | #include "Poco/Net/ServerSocket.h" |
24 | #include "Poco/Net/NetException.h" |
25 | #include "Poco/Thread.h" |
26 | #include "Poco/Buffer.h" |
27 | |
28 | |
29 | using Poco::Net::HTTPClientSession; |
30 | using Poco::Net::HTTPRequest; |
31 | using Poco::Net::HTTPResponse; |
32 | using Poco::Net::HTTPServerRequest; |
33 | using Poco::Net::HTTPServerResponse; |
34 | using Poco::Net::SocketStream; |
35 | using Poco::Net::WebSocket; |
36 | using Poco::Net::WebSocketException; |
37 | |
38 | |
39 | namespace |
40 | { |
41 | class WebSocketRequestHandler: public Poco::Net::HTTPRequestHandler |
42 | { |
43 | public: |
44 | WebSocketRequestHandler(std::size_t bufSize = 1024): _bufSize(bufSize) |
45 | { |
46 | } |
47 | |
48 | void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) |
49 | { |
50 | try |
51 | { |
52 | WebSocket ws(request, response); |
53 | Poco::Buffer<char> buffer(_bufSize); |
54 | int flags; |
55 | int n; |
56 | do |
57 | { |
58 | n = ws.receiveFrame(buffer.begin(), static_cast<int>(buffer.size()), flags); |
59 | if (n == 0) |
60 | break; |
61 | ws.sendFrame(buffer.begin(), n, flags); |
62 | } |
63 | while (n > 0 || (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE); |
64 | } |
65 | catch (WebSocketException& exc) |
66 | { |
67 | switch (exc.code()) |
68 | { |
69 | case WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION: |
70 | response.set("Sec-WebSocket-Version" , WebSocket::WEBSOCKET_VERSION); |
71 | // fallthrough |
72 | case WebSocket::WS_ERR_NO_HANDSHAKE: |
73 | case WebSocket::WS_ERR_HANDSHAKE_NO_VERSION: |
74 | case WebSocket::WS_ERR_HANDSHAKE_NO_KEY: |
75 | response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST); |
76 | response.setContentLength(0); |
77 | response.send(); |
78 | break; |
79 | } |
80 | } |
81 | } |
82 | |
83 | private: |
84 | std::size_t _bufSize; |
85 | }; |
86 | |
87 | class WebSocketRequestHandlerFactory: public Poco::Net::HTTPRequestHandlerFactory |
88 | { |
89 | public: |
90 | WebSocketRequestHandlerFactory(std::size_t bufSize = 1024): _bufSize(bufSize) |
91 | { |
92 | } |
93 | |
94 | Poco::Net::HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request) |
95 | { |
96 | return new WebSocketRequestHandler(_bufSize); |
97 | } |
98 | |
99 | private: |
100 | std::size_t _bufSize; |
101 | }; |
102 | } |
103 | |
104 | |
105 | WebSocketTest::WebSocketTest(const std::string& name): CppUnit::TestCase(name) |
106 | { |
107 | } |
108 | |
109 | |
110 | WebSocketTest::~WebSocketTest() |
111 | { |
112 | } |
113 | |
114 | |
115 | void WebSocketTest::testWebSocket() |
116 | { |
117 | Poco::Net::ServerSocket ss(0); |
118 | Poco::Net::HTTPServer server(new WebSocketRequestHandlerFactory, ss, new Poco::Net::HTTPServerParams); |
119 | server.start(); |
120 | |
121 | Poco::Thread::sleep(200); |
122 | |
123 | HTTPClientSession cs("127.0.0.1" , ss.address().port()); |
124 | HTTPRequest request(HTTPRequest::HTTP_GET, "/ws" , HTTPRequest::HTTP_1_1); |
125 | HTTPResponse response; |
126 | WebSocket ws(cs, request, response); |
127 | |
128 | std::string payload("x" ); |
129 | ws.sendFrame(payload.data(), (int) payload.size()); |
130 | char buffer[1024] = {}; |
131 | int flags; |
132 | int n = ws.receiveFrame(buffer, sizeof(buffer), flags); |
133 | assertTrue (n == payload.size()); |
134 | assertTrue (payload.compare(0, payload.size(), buffer, n) == 0); |
135 | assertTrue (flags == WebSocket::FRAME_TEXT); |
136 | |
137 | for (int i = 2; i < 20; i++) |
138 | { |
139 | payload.assign(i, 'x'); |
140 | ws.sendFrame(payload.data(), (int) payload.size()); |
141 | n = ws.receiveFrame(buffer, sizeof(buffer), flags); |
142 | assertTrue (n == payload.size()); |
143 | assertTrue (payload.compare(0, payload.size(), buffer, n) == 0); |
144 | assertTrue (flags == WebSocket::FRAME_TEXT); |
145 | |
146 | ws.sendFrame(payload.data(), (int) payload.size()); |
147 | Poco::Buffer<char> pocobuffer(0); |
148 | assertTrue(0 == pocobuffer.size()); |
149 | n = ws.receiveFrame(pocobuffer, flags); |
150 | assertTrue (n == payload.size()); |
151 | assertTrue (n == pocobuffer.size()); |
152 | assertTrue (payload.compare(0, payload.size(), pocobuffer.begin(), n) == 0); |
153 | assertTrue (flags == WebSocket::FRAME_TEXT); |
154 | } |
155 | |
156 | for (int i = 125; i < 129; i++) |
157 | { |
158 | payload.assign(i, 'x'); |
159 | ws.sendFrame(payload.data(), (int) payload.size()); |
160 | n = ws.receiveFrame(buffer, sizeof(buffer), flags); |
161 | assertTrue (n == payload.size()); |
162 | assertTrue (payload.compare(0, payload.size(), buffer, n) == 0); |
163 | assertTrue (flags == WebSocket::FRAME_TEXT); |
164 | |
165 | ws.sendFrame(payload.data(), (int) payload.size()); |
166 | Poco::Buffer<char> pocobuffer(0); |
167 | n = ws.receiveFrame(pocobuffer, flags); |
168 | assertTrue (n == payload.size()); |
169 | assertTrue (payload.compare(0, payload.size(), pocobuffer.begin(), n) == 0); |
170 | assertTrue (flags == WebSocket::FRAME_TEXT); |
171 | } |
172 | |
173 | payload = "Hello, world!" ; |
174 | ws.sendFrame(payload.data(), (int) payload.size()); |
175 | n = ws.receiveFrame(buffer, sizeof(buffer), flags); |
176 | assertTrue (n == payload.size()); |
177 | assertTrue (payload.compare(0, payload.size(), buffer, n) == 0); |
178 | assertTrue (flags == WebSocket::FRAME_TEXT); |
179 | |
180 | payload = "Hello, universe!" ; |
181 | ws.sendFrame(payload.data(), (int) payload.size(), WebSocket::FRAME_BINARY); |
182 | n = ws.receiveFrame(buffer, sizeof(buffer), flags); |
183 | assertTrue (n == payload.size()); |
184 | assertTrue (payload.compare(0, payload.size(), buffer, n) == 0); |
185 | assertTrue (flags == WebSocket::FRAME_BINARY); |
186 | |
187 | ws.shutdown(); |
188 | n = ws.receiveFrame(buffer, sizeof(buffer), flags); |
189 | assertTrue (n == 2); |
190 | assertTrue ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_CLOSE); |
191 | |
192 | server.stop(); |
193 | } |
194 | |
195 | |
196 | void WebSocketTest::testWebSocketLarge() |
197 | { |
198 | const int msgSize = 64000; |
199 | |
200 | Poco::Net::ServerSocket ss(0); |
201 | Poco::Net::HTTPServer server(new WebSocketRequestHandlerFactory(msgSize), ss, new Poco::Net::HTTPServerParams); |
202 | server.start(); |
203 | |
204 | Poco::Thread::sleep(200); |
205 | |
206 | HTTPClientSession cs("127.0.0.1" , ss.address().port()); |
207 | HTTPRequest request(HTTPRequest::HTTP_GET, "/ws" , HTTPRequest::HTTP_1_1); |
208 | HTTPResponse response; |
209 | WebSocket ws(cs, request, response); |
210 | ws.setSendBufferSize(msgSize); |
211 | ws.setReceiveBufferSize(msgSize); |
212 | std::string payload(msgSize, 'x'); |
213 | SocketStream sstr(ws); |
214 | sstr << payload; |
215 | sstr.flush(); |
216 | |
217 | char buffer[msgSize + 1] = {}; |
218 | int flags; |
219 | int n = 0; |
220 | do |
221 | { |
222 | n += ws.receiveFrame(buffer + n, sizeof(buffer) - n, flags); |
223 | } while (n > 0 && n < msgSize); |
224 | |
225 | assertTrue (n == payload.size()); |
226 | assertTrue (payload.compare(0, payload.size(), buffer, n) == 0); |
227 | } |
228 | |
229 | |
230 | void WebSocketTest::testOneLargeFrame(int msgSize) |
231 | { |
232 | Poco::Net::ServerSocket ss(0); |
233 | Poco::Net::HTTPServer server(new WebSocketRequestHandlerFactory(msgSize), ss, new Poco::Net::HTTPServerParams); |
234 | server.start(); |
235 | |
236 | Poco::Thread::sleep(200); |
237 | |
238 | HTTPClientSession cs("127.0.0.1" , ss.address().port()); |
239 | HTTPRequest request(HTTPRequest::HTTP_GET, "/ws" , HTTPRequest::HTTP_1_1); |
240 | HTTPResponse response; |
241 | WebSocket ws(cs, request, response); |
242 | ws.setSendBufferSize(msgSize); |
243 | ws.setReceiveBufferSize(msgSize); |
244 | std::string payload(msgSize, 'x'); |
245 | |
246 | ws.sendFrame(payload.data(), msgSize); |
247 | |
248 | Poco::Buffer<char> buffer(msgSize); |
249 | int flags; |
250 | int n; |
251 | |
252 | n = ws.receiveFrame(buffer.begin(), static_cast<int>(buffer.size()), flags); |
253 | assertTrue (n == payload.size()); |
254 | assertTrue (payload.compare(0, payload.size(), buffer.begin(), n) == 0); |
255 | |
256 | ws.sendFrame(payload.data(), msgSize); |
257 | |
258 | Poco::Buffer<char> pocobuffer(0); |
259 | |
260 | n = ws.receiveFrame(pocobuffer, flags); |
261 | assertTrue (n == payload.size()); |
262 | assertTrue (payload.compare(0, payload.size(), pocobuffer.begin(), n) == 0); |
263 | } |
264 | |
265 | |
266 | void WebSocketTest::testWebSocketLargeInOneFrame() |
267 | { |
268 | testOneLargeFrame(64000); |
269 | testOneLargeFrame(70000); |
270 | } |
271 | |
272 | |
273 | void WebSocketTest::setUp() |
274 | { |
275 | } |
276 | |
277 | |
278 | void WebSocketTest::tearDown() |
279 | { |
280 | } |
281 | |
282 | |
283 | CppUnit::Test* WebSocketTest::suite() |
284 | { |
285 | CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("WebSocketTest" ); |
286 | |
287 | CppUnit_addTest(pSuite, WebSocketTest, testWebSocket); |
288 | CppUnit_addTest(pSuite, WebSocketTest, testWebSocketLarge); |
289 | CppUnit_addTest(pSuite, WebSocketTest, testWebSocketLargeInOneFrame); |
290 | |
291 | return pSuite; |
292 | } |
293 | |