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