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
29using Poco::Net::HTTPClientSession;
30using Poco::Net::HTTPRequest;
31using Poco::Net::HTTPResponse;
32using Poco::Net::HTTPServerRequest;
33using Poco::Net::HTTPServerResponse;
34using Poco::Net::SocketStream;
35using Poco::Net::WebSocket;
36using Poco::Net::WebSocketException;
37
38
39namespace
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
105WebSocketTest::WebSocketTest(const std::string& name): CppUnit::TestCase(name)
106{
107}
108
109
110WebSocketTest::~WebSocketTest()
111{
112}
113
114
115void 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
196void 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
230void 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
266void WebSocketTest::testWebSocketLargeInOneFrame()
267{
268 testOneLargeFrame(64000);
269 testOneLargeFrame(70000);
270}
271
272
273void WebSocketTest::setUp()
274{
275}
276
277
278void WebSocketTest::tearDown()
279{
280}
281
282
283CppUnit::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