1 //
2 // HTTPSClientSessionTest.cpp
3 //
4 // Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
5 // and Contributors.
6 //
7 // SPDX-License-Identifier: BSL-1.0
8 //
9
10
11 #include "HTTPSClientSessionTest.h"
12 #include "CppUnit/TestCaller.h"
13 #include "CppUnit/TestSuite.h"
14 #include "Poco/Net/HTTPSClientSession.h"
15 #include "Poco/Net/HTTPRequest.h"
16 #include "Poco/Net/HTTPRequestHandler.h"
17 #include "Poco/Net/HTTPRequestHandlerFactory.h"
18 #include "Poco/Net/HTTPResponse.h"
19 #include "Poco/Net/HTTPServer.h"
20 #include "Poco/Net/HTTPServerResponse.h"
21 #include "Poco/Net/HTTPServerRequest.h"
22 #include "Poco/Net/HTTPServerParams.h"
23 #include "Poco/Net/SecureStreamSocket.h"
24 #include "Poco/Net/Context.h"
25 #include "Poco/Net/Session.h"
26 #include "Poco/Net/SSLManager.h"
27 #include "Poco/Net/SSLException.h"
28 #include "Poco/Util/Application.h"
29 #include "Poco/Util/AbstractConfiguration.h"
30 #include "Poco/StreamCopier.h"
31 #include "Poco/Exception.h"
32 #include "Poco/DateTimeFormatter.h"
33 #include "Poco/DateTimeFormat.h"
34 #include "Poco/Thread.h"
35 #include "HTTPSTestServer.h"
36 #include <istream>
37 #include <ostream>
38 #include <sstream>
39
40
41 using namespace Poco::Net;
42 using Poco::Util::Application;
43 using Poco::StreamCopier;
44 using Poco::Thread;
45
46
47 class TestRequestHandler: public HTTPRequestHandler
48 /// Return a HTML document with the current date and time.
49 {
50 public:
TestRequestHandler()51 TestRequestHandler()
52 {
53 }
54
handleRequest(HTTPServerRequest & request,HTTPServerResponse & response)55 void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
56 {
57 response.setChunkedTransferEncoding(true);
58 response.setContentType(request.getContentType());
59 std::ostream& ostr = response.send();
60 Poco::StreamCopier::copyStream(request.stream(), ostr);
61 }
62
63 };
64
65
66 class TestRequestHandlerFactory: public HTTPRequestHandlerFactory
67 {
68 public:
TestRequestHandlerFactory()69 TestRequestHandlerFactory()
70 {
71 }
72
createRequestHandler(const HTTPServerRequest & request)73 HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request)
74 {
75 return new TestRequestHandler();
76 }
77 };
78
79
HTTPSClientSessionTest(const std::string & name)80 HTTPSClientSessionTest::HTTPSClientSessionTest(const std::string& name): CppUnit::TestCase(name)
81 {
82 }
83
84
~HTTPSClientSessionTest()85 HTTPSClientSessionTest::~HTTPSClientSessionTest()
86 {
87 }
88
89
testGetSmall()90 void HTTPSClientSessionTest::testGetSmall()
91 {
92 HTTPSTestServer srv;
93 HTTPSClientSession s("127.0.0.1", srv.port());
94 HTTPRequest request(HTTPRequest::HTTP_GET, "/small");
95 s.sendRequest(request);
96 HTTPResponse response;
97 std::istream& rs = s.receiveResponse(response);
98 assertTrue (response.getContentLength() == HTTPSTestServer::SMALL_BODY.length());
99 assertTrue (response.getContentType() == "text/plain");
100 std::ostringstream ostr;
101 StreamCopier::copyStream(rs, ostr);
102 assertTrue (ostr.str() == HTTPSTestServer::SMALL_BODY);
103 }
104
105
testGetLarge()106 void HTTPSClientSessionTest::testGetLarge()
107 {
108 HTTPSTestServer srv;
109 HTTPSClientSession s("127.0.0.1", srv.port());
110 HTTPRequest request(HTTPRequest::HTTP_GET, "/large");
111 s.sendRequest(request);
112 HTTPResponse response;
113 std::istream& rs = s.receiveResponse(response);
114 assertTrue (response.getContentLength() == HTTPSTestServer::LARGE_BODY.length());
115 assertTrue (response.getContentType() == "text/plain");
116 std::ostringstream ostr;
117 StreamCopier::copyStream(rs, ostr);
118 assertTrue (ostr.str() == HTTPSTestServer::LARGE_BODY);
119 }
120
121
testHead()122 void HTTPSClientSessionTest::testHead()
123 {
124 HTTPSTestServer srv;
125 HTTPSClientSession s("127.0.0.1", srv.port());
126 HTTPRequest request(HTTPRequest::HTTP_HEAD, "/large");
127 s.sendRequest(request);
128 HTTPResponse response;
129 std::istream& rs = s.receiveResponse(response);
130 assertTrue (response.getContentLength() == HTTPSTestServer::LARGE_BODY.length());
131 assertTrue (response.getContentType() == "text/plain");
132 std::ostringstream ostr;
133 assertTrue (StreamCopier::copyStream(rs, ostr) == 0);
134 }
135
136
testPostSmallIdentity()137 void HTTPSClientSessionTest::testPostSmallIdentity()
138 {
139 HTTPSTestServer srv;
140 HTTPSClientSession s("127.0.0.1", srv.port());
141 HTTPRequest request(HTTPRequest::HTTP_POST, "/echo");
142 std::string body("this is a random request body\r\n0\r\n");
143 request.setContentLength((int) body.length());
144 s.sendRequest(request) << body;
145 HTTPResponse response;
146 std::istream& rs = s.receiveResponse(response);
147 assertTrue (response.getContentLength() == body.length());
148 std::ostringstream ostr;
149 StreamCopier::copyStream(rs, ostr);
150 assertTrue (ostr.str() == body);
151 }
152
153
testPostLargeIdentity()154 void HTTPSClientSessionTest::testPostLargeIdentity()
155 {
156 HTTPSTestServer srv;
157 HTTPSClientSession s("127.0.0.1", srv.port());
158 HTTPRequest request(HTTPRequest::HTTP_POST, "/echo");
159 std::string body(8000, 'x');
160 body.append("\r\n0\r\n");
161 request.setContentLength((int) body.length());
162 s.sendRequest(request) << body;
163 HTTPResponse response;
164 std::istream& rs = s.receiveResponse(response);
165 assertTrue (response.getContentLength() == body.length());
166 std::ostringstream ostr;
167 StreamCopier::copyStream(rs, ostr);
168 assertTrue (ostr.str() == body);
169 }
170
171
testPostSmallChunked()172 void HTTPSClientSessionTest::testPostSmallChunked()
173 {
174 HTTPSTestServer srv;
175 HTTPSClientSession s("127.0.0.1", srv.port());
176 HTTPRequest request(HTTPRequest::HTTP_POST, "/echo");
177 std::string body("this is a random request body");
178 request.setChunkedTransferEncoding(true);
179 s.sendRequest(request) << body;
180 HTTPResponse response;
181 std::istream& rs = s.receiveResponse(response);
182 assertTrue (response.getChunkedTransferEncoding());
183 assertTrue (response.getContentLength() == HTTPMessage::UNKNOWN_CONTENT_LENGTH);
184 std::ostringstream ostr;
185 StreamCopier::copyStream(rs, ostr);
186 assertTrue (ostr.str() == body);
187 }
188
189
testPostLargeChunked()190 void HTTPSClientSessionTest::testPostLargeChunked()
191 {
192 HTTPSTestServer srv;
193 HTTPSClientSession s("127.0.0.1", srv.port());
194 HTTPRequest request(HTTPRequest::HTTP_POST, "/echo");
195 std::string body(16000, 'x');
196 request.setChunkedTransferEncoding(true);
197 s.sendRequest(request) << body;
198 HTTPResponse response;
199 std::istream& rs = s.receiveResponse(response);
200 assertTrue (response.getChunkedTransferEncoding());
201 assertTrue (response.getContentLength() == HTTPMessage::UNKNOWN_CONTENT_LENGTH);
202 std::ostringstream ostr;
203 StreamCopier::copyStream(rs, ostr);
204 assertTrue (ostr.str() == body);
205 }
206
207
testPostLargeChunkedKeepAlive()208 void HTTPSClientSessionTest::testPostLargeChunkedKeepAlive()
209 {
210 SecureServerSocket svs(32322);
211 HTTPServer srv(new TestRequestHandlerFactory(), svs, new HTTPServerParams());
212 srv.start();
213 try
214 {
215 HTTPSClientSession s("127.0.0.1", srv.port());
216 s.setKeepAlive(true);
217 for (int i = 0; i < 10; ++i)
218 {
219 HTTPRequest request(HTTPRequest::HTTP_POST, "/keepAlive", HTTPMessage::HTTP_1_1);
220 std::string body(16000, 'x');
221 request.setChunkedTransferEncoding(true);
222 s.sendRequest(request) << body;
223 HTTPResponse response;
224 std::istream& rs = s.receiveResponse(response);
225 assertTrue (response.getChunkedTransferEncoding());
226 assertTrue (response.getContentLength() == HTTPMessage::UNKNOWN_CONTENT_LENGTH);
227 std::ostringstream ostr;
228 StreamCopier::copyStream(rs, ostr);
229 assertTrue (ostr.str() == body);
230 }
231 srv.stop();
232 }
233 catch (...)
234 {
235 srv.stop();
236 throw;
237 }
238 }
239
240
testKeepAlive()241 void HTTPSClientSessionTest::testKeepAlive()
242 {
243 HTTPSTestServer srv;
244 HTTPSClientSession s("127.0.0.1", srv.port());
245 s.setKeepAlive(true);
246 HTTPRequest request(HTTPRequest::HTTP_HEAD, "/keepAlive", HTTPMessage::HTTP_1_1);
247 s.sendRequest(request);
248 HTTPResponse response;
249 std::istream& rs1 = s.receiveResponse(response);
250 assertTrue (response.getContentLength() == HTTPSTestServer::SMALL_BODY.length());
251 assertTrue (response.getContentType() == "text/plain");
252 assertTrue (response.getKeepAlive());
253 std::ostringstream ostr1;
254 assertTrue (StreamCopier::copyStream(rs1, ostr1) == 0);
255
256 request.setMethod(HTTPRequest::HTTP_GET);
257 request.setURI("/small");
258 s.sendRequest(request);
259 std::istream& rs2 = s.receiveResponse(response);
260 assertTrue (response.getContentLength() == HTTPSTestServer::SMALL_BODY.length());
261 assertTrue (response.getKeepAlive());
262 std::ostringstream ostr2;
263 StreamCopier::copyStream(rs2, ostr2);
264 assertTrue (ostr2.str() == HTTPSTestServer::SMALL_BODY);
265
266 request.setMethod(HTTPRequest::HTTP_GET);
267 request.setURI("/large");
268 s.sendRequest(request);
269 std::istream& rs3 = s.receiveResponse(response);
270 assertTrue (response.getContentLength() == HTTPMessage::UNKNOWN_CONTENT_LENGTH);
271 assertTrue (response.getChunkedTransferEncoding());
272 assertTrue (response.getKeepAlive());
273 std::ostringstream ostr3;
274 StreamCopier::copyStream(rs3, ostr3);
275 assertTrue (ostr3.str() == HTTPSTestServer::LARGE_BODY);
276
277 request.setMethod(HTTPRequest::HTTP_HEAD);
278 request.setURI("/large");
279 s.sendRequest(request);
280 std::istream& rs4 = s.receiveResponse(response);
281 assertTrue (response.getContentLength() == HTTPSTestServer::LARGE_BODY.length());
282 assertTrue (response.getContentType() == "text/plain");
283 assertTrue (!response.getKeepAlive());
284 std::ostringstream ostr4;
285 assertTrue (StreamCopier::copyStream(rs4, ostr4) == 0);
286 }
287
288
testInterop()289 void HTTPSClientSessionTest::testInterop()
290 {
291 HTTPSClientSession s("secure.appinf.com");
292 HTTPRequest request(HTTPRequest::HTTP_GET, "/public/poco/NetSSL.txt");
293 s.sendRequest(request);
294 X509Certificate cert = s.serverCertificate();
295 HTTPResponse response;
296 std::istream& rs = s.receiveResponse(response);
297 std::ostringstream ostr;
298 StreamCopier::copyStream(rs, ostr);
299 std::string str(ostr.str());
300 assertTrue (str == "This is a test file for NetSSL.\n");
301 assertTrue (cert.commonName() == "secure.appinf.com" || cert.commonName() == "*.appinf.com");
302 }
303
304
testProxy()305 void HTTPSClientSessionTest::testProxy()
306 {
307 HTTPSTestServer srv;
308 HTTPSClientSession s("secure.appinf.com");
309 s.setProxy(
310 Application::instance().config().getString("testsuite.proxy.host"),
311 Application::instance().config().getInt("testsuite.proxy.port")
312 );
313 HTTPRequest request(HTTPRequest::HTTP_GET, "/public/poco/NetSSL.txt");
314 s.sendRequest(request);
315 X509Certificate cert = s.serverCertificate();
316 HTTPResponse response;
317 std::istream& rs = s.receiveResponse(response);
318 std::ostringstream ostr;
319 StreamCopier::copyStream(rs, ostr);
320 std::string str(ostr.str());
321 assertTrue (str == "This is a test file for NetSSL.\n");
322 assertTrue (cert.commonName() == "secure.appinf.com" || cert.commonName() == "*.appinf.com");
323 }
324
325
testCachedSession()326 void HTTPSClientSessionTest::testCachedSession()
327 {
328 // ensure OpenSSL machinery is fully setup
329 Context::Ptr pDefaultServerContext = SSLManager::instance().defaultServerContext();
330 Context::Ptr pDefaultClientContext = SSLManager::instance().defaultClientContext();
331
332 Context::Ptr pServerContext = new Context(
333 Context::SERVER_USE,
334 Application::instance().config().getString("openSSL.server.privateKeyFile"),
335 Application::instance().config().getString("openSSL.server.privateKeyFile"),
336 Application::instance().config().getString("openSSL.server.caConfig"),
337 Context::VERIFY_NONE,
338 9,
339 true,
340 "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
341 pServerContext->enableSessionCache(true, "TestSuite");
342 pServerContext->setSessionTimeout(10);
343 pServerContext->setSessionCacheSize(1000);
344 pServerContext->disableStatelessSessionResumption();
345
346 HTTPSTestServer srv(pServerContext);
347
348 Context::Ptr pClientContext = new Context(
349 Context::CLIENT_USE,
350 Application::instance().config().getString("openSSL.client.privateKeyFile"),
351 Application::instance().config().getString("openSSL.client.privateKeyFile"),
352 Application::instance().config().getString("openSSL.client.caConfig"),
353 Context::VERIFY_RELAXED,
354 9,
355 true,
356 "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
357 pClientContext->enableSessionCache(true);
358
359 HTTPSClientSession s1("127.0.0.1", srv.port(), pClientContext);
360 HTTPRequest request1(HTTPRequest::HTTP_GET, "/small");
361 s1.sendRequest(request1);
362 Session::Ptr pSession1 = s1.sslSession();
363 HTTPResponse response1;
364 std::istream& rs1 = s1.receiveResponse(response1);
365 assertTrue (response1.getContentLength() == HTTPSTestServer::SMALL_BODY.length());
366 assertTrue (response1.getContentType() == "text/plain");
367 std::ostringstream ostr1;
368 StreamCopier::copyStream(rs1, ostr1);
369 assertTrue (ostr1.str() == HTTPSTestServer::SMALL_BODY);
370
371 HTTPSClientSession s2("127.0.0.1", srv.port(), pClientContext, pSession1);
372 HTTPRequest request2(HTTPRequest::HTTP_GET, "/small");
373 s2.sendRequest(request2);
374 Session::Ptr pSession2 = s2.sslSession();
375 HTTPResponse response2;
376 std::istream& rs2 = s2.receiveResponse(response2);
377 assertTrue (response2.getContentLength() == HTTPSTestServer::SMALL_BODY.length());
378 assertTrue (response2.getContentType() == "text/plain");
379 std::ostringstream ostr2;
380 StreamCopier::copyStream(rs2, ostr2);
381 assertTrue (ostr2.str() == HTTPSTestServer::SMALL_BODY);
382
383 assertTrue (pSession1 == pSession2);
384
385 HTTPRequest request3(HTTPRequest::HTTP_GET, "/small");
386 s2.sendRequest(request3);
387 Session::Ptr pSession3 = s2.sslSession();
388 HTTPResponse response3;
389 std::istream& rs3 = s2.receiveResponse(response3);
390 assertTrue (response3.getContentLength() == HTTPSTestServer::SMALL_BODY.length());
391 assertTrue (response3.getContentType() == "text/plain");
392 std::ostringstream ostr3;
393 StreamCopier::copyStream(rs3, ostr3);
394 assertTrue (ostr3.str() == HTTPSTestServer::SMALL_BODY);
395
396 assertTrue (pSession1 == pSession3);
397
398 Thread::sleep(15000); // wait for session to expire
399 pServerContext->flushSessionCache();
400
401 HTTPRequest request4(HTTPRequest::HTTP_GET, "/small");
402 s2.sendRequest(request4);
403 Session::Ptr pSession4 = s2.sslSession();
404 HTTPResponse response4;
405 std::istream& rs4 = s2.receiveResponse(response4);
406 assertTrue (response4.getContentLength() == HTTPSTestServer::SMALL_BODY.length());
407 assertTrue (response4.getContentType() == "text/plain");
408 std::ostringstream ostr4;
409 StreamCopier::copyStream(rs4, ostr4);
410 assertTrue (ostr4.str() == HTTPSTestServer::SMALL_BODY);
411
412 assertTrue (pSession1 != pSession4);
413 }
414
415
testUnknownContentLength()416 void HTTPSClientSessionTest::testUnknownContentLength()
417 {
418 HTTPSTestServer srv;
419 HTTPSClientSession s("127.0.0.1", srv.port());
420 HTTPRequest request(HTTPRequest::HTTP_GET, "/nolength");
421 s.sendRequest(request);
422 HTTPResponse response;
423 std::istream& rs = s.receiveResponse(response);
424 assertTrue (response.getContentLength() == HTTPMessage::UNKNOWN_CONTENT_LENGTH);
425 assertTrue (response.getContentType() == "text/plain");
426 std::ostringstream ostr;
427 StreamCopier::copyStream(rs, ostr);
428 assertTrue (ostr.str() == HTTPSTestServer::SMALL_BODY);
429 }
430
testServerAbort()431 void HTTPSClientSessionTest::testServerAbort()
432 {
433 HTTPSTestServer srv;
434 HTTPSClientSession s("127.0.0.1", srv.port());
435 HTTPRequest request(HTTPRequest::HTTP_GET, "/nolength/connection/abort");
436 s.sendRequest(request);
437 HTTPResponse response;
438 std::istream& rs = s.receiveResponse(response);
439 assertTrue (response.getContentLength() == HTTPMessage::UNKNOWN_CONTENT_LENGTH);
440 assertTrue (response.getContentType() == "text/plain");
441 std::ostringstream ostr;
442 StreamCopier::copyStream(rs, ostr);
443 assertTrue (ostr.str() == HTTPSTestServer::SMALL_BODY);
444 assertTrue ( dynamic_cast<const Poco::Net::SSLConnectionUnexpectedlyClosedException*>(
445 s.networkException()) != NULL );
446 }
447
448
setUp()449 void HTTPSClientSessionTest::setUp()
450 {
451 }
452
453
tearDown()454 void HTTPSClientSessionTest::tearDown()
455 {
456 }
457
458
suite()459 CppUnit::Test* HTTPSClientSessionTest::suite()
460 {
461 CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("HTTPSClientSessionTest");
462
463 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testGetSmall);
464 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testGetLarge);
465 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testHead);
466 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testPostSmallIdentity);
467 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testPostLargeIdentity);
468 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testPostSmallChunked);
469 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testPostLargeChunked);
470 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testPostLargeChunkedKeepAlive);
471 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testKeepAlive);
472 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testInterop);
473 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testProxy);
474 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testCachedSession);
475 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testUnknownContentLength);
476 CppUnit_addTest(pSuite, HTTPSClientSessionTest, testServerAbort);
477
478 return pSuite;
479 }
480