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